7

フォームでマウスのシングル クリック イベントとダブル クリック イベントの両方を処理している状況があります。どちらの場合も何かをロードする必要がありますが、ダブルクリックが発生したときに、シングル クリック イベントに関連付けられたコードを実行したくありません。

マウス クリックをインターセプトし、ダブルかシングルかを確認してから、適切なイベントを適切に実行する方法はありますか?

おそらく、ウィンドウの WndProc をインターセプトするか何かでしょうか?

4

2 に答える 2

6

いいえ、タイムマシンがなければ、それはほとんど不可能です。そして、Windowsがダブルクリックとシングルクリックをどのように区別するかを理解すれば、それは実際には意味がありません。

Raymond Chen(Windows Shellチームの開発者)は、「Windowsがシングルクリックをダブルクリックに変換する方法の論理的帰結」というタイトルのブログエントリで正確に説明していることがわかりました。

具体的には、関数で指定された間隔内に2回目のクリックが発生したため、Windowsは何かをダブルクリックとして解釈することしか認識していません。何かがシングルクリックになるのかダブルクリックになるのかを事前に判断するには(レイモンドが雄弁に言っているように)透視が必要になるため、ウィンドウマネージャーは先に進み、最初のクリックが受信されるとすぐにメッセージを送信します。メッセージは、2回目のクリックが実際にダブルクリックを表すことが確認された後、後でのみ送信されます。結果として、アプリケーションは、受信したメッセージごとに常に2つのメッセージを受信します。GetDoubleClickTimeWM_LBUTTONDOWNWM_LBUTTONDBLCLK WM_LBUTTONDOWNWM_LBUTTONDBLCLK

これで、.NET Frameworkの設計者は、このプロセスがどのように機能するかを理解し、それに応じて発生するイベントを設計しました。もちろん、ダブルクリックの前に常に発生するシングルクリックについては何もできませんが、ユーザーがダブルクリックイベントの一部であると判断された場合は、セカンドクリックメッセージを抑制することができました。Control.MouseClickイベントのドキュメント(WM_LBUTTONDOWNメッセージにほぼ対応)には、次のように書かれています。

ユーザーのオペレーティングシステムのマウス設定によって決定されるように、十分に近い時間に発生する2回のシングルクリックMouseDoubleClickは、2番目のイベントの代わりにイベントを生成しMouseClickます。

ただし、上記でリンクしたRaymondのブログ記事では、ダブルクリックアクションがシングルクリックアクションとは無関係である設計を主張するアプリや開発者向けの可能な回避策を提案しています(ただし、どちらも実際にこれを行うことはお勧めしません) )::

ここで、ダブルクリックアクションをシングルクリックアクションとは無関係にするという疑わしい設計を継続したいプログラムであるとします。職業はなんですか?

さて、あなたができることの1つは、ミリ秒単位で起動するようWM_LBUTTONDOWNにタイマーを設定する以外は、メッセージの受信時に何もしないことです。GetDoubleClickTime()[午前10時修正]WM_LBUTTONDBLCLKその時間内にメッセージが表示された場合は、結局ダブルクリックでした。そうでない場合は、シングルクリックである必要があるため、シングルクリックアクションを実行できます(少し遅れますが)。

于 2011-01-27T09:41:49.597 に答える
4

これは、あなたが要求したことを行うためのコードです。

Public Class Form1
    Const WM_LBUTTONDOWN As Integer = &H201
    Const WM_LBUTTONDBLCLK As Integer = &H203

    Private WithEvents tmrDoubleClicks As Timer

    Dim isDblClk As Boolean
    Dim firstClickTime As Date
    Dim doubleClickInterval As Integer

    Sub New()

        ' This call is required by the designer.
        InitializeComponent()
        tmrDoubleClicks = New Timer

        ' Add any initialization after the InitializeComponent() call.
        tmrDoubleClicks.Interval = 50
        doubleClickInterval = CInt(Val(Microsoft.Win32.Registry.CurrentUser.
                                       OpenSubKey("Control Panel\Mouse").
                                       GetValue("DoubleClickSpeed", 1000)))
    End Sub

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
            If disposing AndAlso tmrDoubleClicks IsNot Nothing Then
                tmrDoubleClicks.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case WM_LBUTTONDOWN
                If Not isDblClk Then
                    firstClickTime = Now
                    tmrDoubleClicks.Start()
                End If

            Case WM_LBUTTONDBLCLK
                isDblClk = True
                tmrDoubleClicks.Stop()
                DoubleClickActivity()
                isDblClk = False

            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

    Private Sub DoubleClickActivity()
        'implement double click activity here
        Dim r As New Random(Now.TimeOfDay.Seconds)
        Me.BackColor = Color.FromArgb(r.Next(0, 255), 
                                      r.Next(0, 255), 
                                      r.Next(0, 255))
    End Sub

    Private Sub SingleClickActivity()
        'implement single click activity here
        Beep()
    End Sub

    Private Sub tmrDoubleClicks_Tick(ByVal sender As Object, 
                                     ByVal e As System.EventArgs 
                                    ) Handles tmrDoubleClicks.Tick

        If Now.Subtract(firstClickTime).TotalMilliseconds > 
          doubleClickInterval Then

            'since there was no other click within the doubleclick speed,
            'stop waiting and fire the single click activity
            isDblClk = False
            tmrDoubleClicks.Stop()
            SingleClickActivity()
        End If
    End Sub
End Class

このコードの要点は、ダブルクリック時間が経過するまでクリック イベントの発生を遅らせることです。その時間内に別のクリック イベントが発生した場合、クリック イベントを呼び出さずにダブルクリック イベントが呼び出されます。ただし、ダブルクリックがない場合は、クリック イベントが呼び出されます。

この遅延は、ダブルクリックの速度が速いコンピューターで特に顕著です。一般的なコンピューターでは、ダブルクリックの速度は 500 ミリ秒であるため、コードはクリックが発生してから 500 ミリ秒から 600 ミリ秒の間にクリック イベントを実行します。

于 2011-01-28T10:30:32.410 に答える