Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Making DoubleClick generate two MouseDown events? 1

Status
Not open for further replies.

AndyGroom

Programmer
May 23, 2001
972
GB
Is it possible to force VB to fire a MouseDown event every time the user actually clicks a control (in my case a PictureBox) even if they do a double click - which would fire two MouseDown events instead of just one?

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
Sure - but we have to think a bit laterally.

Step 1
Realise that the doubleclick timing can probably be controlled through an API, since we can definitely change it through control panel

Step 2
Find that API: SetDoubleClickTime

Excellent, so we could um ... yes ... just set the doubleclicktime to 0? No, documentation says that 0 means we get the default (which is whatever is set in Control Panel, normally 500ms). OK, Ok, so we can set it to 1ms. Nobody can doubleclick that fast ...

Step 3
Oh dear ... discover that setting the doubleclick time a) affects every window in the system, and b) a whole bunch of other user interface time values are based off the doubleclick timing (e.g. the various tooltip timings and scrollbar autorepeating delays). So we can't just set it to 1ms and leave it at that. Windows will start acting wierdly

Hmm - so what we need to do is set the doubleclick down to a silly minimum on receiving the first click. That will cause the doubleclick to timeout, thus the next click will be a normal click - and here's the important bit - whether or not the doubleclick time is set back to its original setting or not ... and we want to set it back because we don't want all those other windows to be affected.

Step 4
Determine SetDoubleClickTime's companion call: GetDoubleClickTime

So something like the following works:
Code:
[blue]Option Explicit

Private Declare Function GetDoubleClickTime Lib "user32.dll" () As Long
Private Declare Function SetDoubleClickTime Lib "user32.dll" (ByVal wCount As Long) As Long


Private Sub Command1_Click()
    Debug.Print GetDoubleClickTime
End Sub

Private Sub Picture1_Click()
    Dim oldclick As Long
    oldclick = GetDoubleClickTime
    SetDoubleClickTime (1) ' Effectively eats doubleclick
    SetDoubleClickTime oldclick
    Debug.Print "Click"
End Sub

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Debug.Print "Mousedown"
End Sub[/blue]

You should now see each and every click (and mousedown) being registered on the picture box, and no doubleclick.

If anyone has a more elegant way of doing this I'd be pleased to hear it.

 
Any solution is welcome!

I wondered if it was possible to intercept the wm_lbuttondown message and eat it, but that doesn't seem to work. I also hoped that something as simple as ReleaseCapture might work but no.

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
I've tried this code but I can't seem to get it to work. If I double-click the picturebox it only generates one 'click' line in the debug window when I believe there should be two.

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
The code does not work for me too. I also get one click/mouse down event followed by a double-click event.

I would suggest subclassing as the implementation is easy and clean.

You don't need to intercept button-down messages. Instead, you need to intercept double-click messages and transform them to button-down messages.

See the following example. Insert the following code in your form having a picturebox.
___
[tt]
Private Sub Form_Load()
Const GWL_WNDPROC = -4
lpWndFunc = SetWindowLong(Picture1.hwnd, GWL_WNDPROC, AddressOf WndProc)
End Sub

Private Sub Picture1_Click()
Debug.Print Time, "Click"
End Sub

Private Sub Picture1_DblClick()
Debug.Print Time, "Double Click"
End Sub

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Debug.Print Time, "Mouse Down", Button, Shift, X, Y
End Sub

Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Debug.Print Time, "Mouse Up", Button, Shift, X, Y
End Sub[/tt]
___

The following code goes in a module used for subclassing.
___
[tt]
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public lpWndFunc As Long
Const WM_LBUTTONDBLCLK = &H203
Const WM_LBUTTONDOWN = &H201
Const WM_MBUTTONDBLCLK = &H209
Const WM_MBUTTONDOWN = &H207
Const WM_RBUTTONDBLCLK = &H206
Const WM_RBUTTONDOWN = &H204
Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'convert double-click messages to button-down messages
If uMsg = WM_LBUTTONDBLCLK Then uMsg = WM_LBUTTONDOWN
If uMsg = WM_RBUTTONDBLCLK Then uMsg = WM_RBUTTONDOWN
If uMsg = WM_MBUTTONDBLCLK Then uMsg = WM_MBUTTONDOWN
WndProc = CallWindowProc(lpWndFunc, hwnd, uMsg, wParam, lParam)
End Function[/tt]
___

Run the program and test it. You will see that the double-click event never fires. Instead, you get another pair of mouse down/mouse up events followed by a click event.

The artificially created events also report all the parameters (Button, Shift, X, Y) correctly. This is because the message parameters (wParam/lParam) for button-down and double-click messages are exactly same. The parameters generated by original double-click message are used by the modified button-down message without loosing any information.

Furthermore, the code works for all 3 buttons. You can remove the check for right and middle button messages if you don't use them.
 
Odd - works on my development boxand delivers the required tewo messqages and no double click.

Hmmm ...


Still, the subclassing is a splendid solution. Must start learning about subclassing ;-)
 
Odd - works on my development boxand delivers the required tewo messqages and no double click."

Vodka + typing = bad combo


Thanks Hypetia for the subclassing idea. I don't mean to sound ungrateful but isn't there an easier solution? For example, I can't understand why the picturebox doesn't fire a wm_lbuttondown event each time the mouse is clicked. I could intercept the messages if only VB would generate them! Grrr...

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
Sorry, I tried your code and it is pretty elegant, good solution!

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
Is any code needed in the Form_Unload event? The test code seems to hang VB whenever you close the form.

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
>Vodka + typing = bad combo

:)

But actually just tiredness. Honest.

And today I discover why it worked ... I was accessing the development box via terminal services, which changes the behaviour(which I should have thought of)
 
Code:
Private Sub Form_Unload(Cancel as Integer)
  a& = SetWindowLong(Picture1.hwnd, GWL_WNDPROC, lpWndFunc)
End Sub

- Andy
___________________________________________________________________
If you think nobody cares you're alive, try missing a couple of mortgage payments
 
Elegant?
'DoAction' below simulates a "double mousedown" when you double click. The first button press of a double click generates a mousedown and remembers the co-ordinates and the second press of a double click generates the dbl_click sending the same remembered co-ordinates because the mouse has not moved.

Dim RememberButton As Integer, RememberShift As Integer, RememberX As Single, RememberY As Single

Private Sub Picture1_DblClick()
DoAction
End Sub

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
RememberButton = Button
RememberShift = Shift
RememberX = X
RememberY = Y
DoAction
End Sub

Sub DoAction()
Debug.Print "Action", RememberButton, RememberShift, RememberX, RememberY
End Sub

If you only want one "DoAction' whether you double or single click, just dont use the Dbl_Click at all.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top