2011-01-27 29 views
7

Tengo una situación en la que estoy manejando los dos eventos simples de clic del mouse & en un formulario. En ambos casos, se debe cargar algo, sin embargo, cuando se produce un doble clic, no deseo ejecutar el código adjunto al evento de un solo clic.Interceptar clic simple o doble del mouse - solo ejecutar doble clic en el código al hacer doble clic

¿Hay alguna manera de interceptar los clics del mouse y verificar si son dobles o solos y luego ejecutar el evento correcto?

¿Quizás al interceptar el WndProc de la ventana o algo así?

+0

¿Esto es WinForms o WPF? – ChrisF

+0

esto es WinForms –

Respuesta

6

No, eso es casi imposible a menos que tenga una máquina del tiempo. Y realmente no tiene sentido una vez que comprenda cómo distingue Windows dos clics de un solo clic.

Resulta que Raymond Chen (un desarrollador en el equipo de Windows Shell) explica exactamente eso en una entrada de blog titulada "Logical consequences of the way Windows converts single-clicks into double-clicks".

Específicamente, Windows sólo sabe interpretar algo como un doble clic, porque una segundo clic se ha producido dentro del intervalo especificado por el GetDoubleClickTime function. Debido a que requeriría clarividencia (como lo describe tan elocuentemente Raymond) para determinar por delante de tiempo si algo va a ser un simple o doble clic, el administrador de ventanas sigue adelante y envía un WM_LBUTTONDOWN message tan pronto como se recibe el primer clic. El WM_LBUTTONDBLCLK message solo se envía más tarde, después de que se confirme que el segundo clic representa realmente un doble clic. El resultado es que su aplicación siempre recibirá dos mensajesWM_LBUTTONDOWN por cada mensaje WM_LBUTTONDBLCLK que se reciba.

Ahora, los diseñadores de Framework .NET entendieron cómo funciona este proceso y diseñaron los eventos que se generan en consecuencia. Por supuesto, no pueden hacer nada para que un clic solo ocurra antes de hacer doble clic, pero pudieron suprimir el segundo mensaje de clic si se determina que el usuario pretendía formar parte de un evento de doble clic. A medida que la documentación de la Control.MouseClick event (que se corresponde aproximadamente con el mensaje WM_LBUTTONDOWN) nos dice: clics

dos individuales que se producen suficientemente cerca en el tiempo, según lo determinado por la configuración del ratón del sistema operativo del usuario, se generará un MouseDoubleClick evento en lugar del segundo evento MouseClick.

artículo en el blog de Raymond que he vinculado al anterior, sin embargo, proponer una posible solución para aplicaciones y desarrolladores que insisten en un diseño en el que la acción de doble clic no está relacionada con la acción de un solo clic (aunque ninguno de los dos recomendamos que realmente haga esto):

Supongamos que es un programa que, sin embargo, desea continuar con el dudoso diseño de hacer que la acción de doble clic no esté relacionada con la acción de un solo clic. ¿Qué haces?

Bueno, una cosa que podría hacer es no hacer nada al recibir el mensaje WM_LBUTTONDOWN aparte de configurar un temporizador para disparar en GetDoubleClickTime() milisegundos. [Se corrigió a las 10 a. M.] Si recibes un mensaje de WM_LBUTTONDBLCLK dentro de ese tiempo, entonces fue un doble clic después de todo. Si no lo hace, debe haber sido un solo clic, por lo que puede hacer su acción de un solo clic (aunque un poco tarde).

+0

He borrado mi respuesta ya que me perdí completamente el objetivo de la pregunta. – ChrisF

+0

Esto podría ayudar: http://stackoverflow.com/questions/9553595/how-to-run-same-code-in-click-event-as-the-double-click-event – CrazyTim

4

Aquí está el código para hacer lo que ha solicitado.

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 

El quid de este código es retrasar la activación del clic hasta que el tiempo de doble clic transcurra. Si dentro de ese tiempo, se produce otro evento de clic dentro de ese tiempo, se llama al evento de doble clic sin llamar al evento click. Sin embargo, si no hay doble clic, se llama al evento click.

Este retraso se nota especialmente en las computadoras que tienen una velocidad de doble clic más larga. En una computadora típica, la velocidad de doble clic es de 500 ms, por lo que el código ejecutará el evento de clic en algún lugar entre 500 ms y 600 ms después de que se haya producido un clic.

+1

No pude evitar darme cuenta que nunca llamas al método 'Dispose' para el objeto' Timer' que creas en el constructor. Eso es * casi * digno de un voto negativo de mi parte. –

+0

@Cody: Perdón por eso. Normalmente coloco los métodos 'Dispose' en el archivo Form.Designer.vb (donde está el código generado por el diseñador). Gracias por mencionarlo. –

+0

No es gran cosa, es que demasiadas personas se olvidan de esto o no lo saben. Al publicar una solución completa que es probable que alguien copie y pegue en su IDE, es importante asegurarse de señalar este tipo de cosas. Y, pensándolo mejor, en realidad tiene más sentido agregar el control del temporizador a la colección de 'componentes 'de la forma. De esta forma, el código generado por el diseñador lo eliminará automáticamente sin que nadie tenga que recordar explícitamente agregarlo. 'System.Windows.Forms.Timer' hereda de' Component', después de todo. –

Cuestiones relacionadas