How to differtiate between OnLButtonUp and OnLButtonDblClk in mfc - mfc

i am using OnLButtonUp and OnLButtonDblClk in my application but whenever i double click OnLButtonDblClk and OnLButtonUp both called but i wanted only OnLButtonDblClk to be called not OnLButtonUp . How to do this?

The problem is that whenever the user double clicks there are four messages sent:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
This only happens if the user clicks the second time within the "double click time" (use ::GetDoubleClickTime() to get it).
So what you can do is set a timer (with a timeout value equal to the double click time) when the user first clicks and if the second click comes before the timer goes off, you have a double click and you can disregard the button up message.
If the timer goes off, you call your button-up handler.
This technique has the drawback that it delays a bit the response to "Button Up" or single click, depending how you do it, but there's no easy way to discard just the Button Up messages when there's a double click.
EDIT:
If you just want to discard the second WM_LBUTTONUP, you can use a flag. You set it when you receive WM_LBUTTONDBLCLK. Then in the handler for WM_LBUTTONUP you do nothing if it's set (and then you clear it, of course).

OnLButtonUp(UINT nFlags, CPoint point)
{
Sleep(::GetDoubleClickTime());
MSG msg;
if( ::PeekMessage(&msg, NULL, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_NOREMOVE) )
return; // LEFT CONTROL TO DBL CLICK ;-)
// NORMAL OnLButtonUp
}

Related

How to use GetAsyncKeyState to see key was pressed for x seconds

I am trying to create a code which will detect if the mouse button has been pressed. So far i have a code which will detect if the button has been pressed once. But it isn't letting me check if the button was continuously pressed. For e.g left mouse button pressed, this will start a timer, after 0.5 seconds it will check again and if it is still down output something.
I want to set it up like this
while (true)
{
if (GetAsyncKeyState(VK_LBUTTON) & (0x8000 != 0))
{
cout << ("left button pressed") << endl;
Sleep(500);
if (GetAsyncKeyState(VK_LBUTTON) & (0x8000 != 0))
{
cout << ("Left button held down") << endl;
}
}
}
However, it does not work, it only outputs the second statement if i double click in quick succession.
Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.
The msdn website says that. Does this mean i should check if it is UP after the time to get the result i want.
GetAsyncKeyState just tells you the state right now, it should not be used to monitor possible changes over time!
If you want to track the mouse no matter which application is receiving the input then you should use SetWindowsHookEx to install a low-level mouse hook.
If you only care about mouse events in your own window then it would be better to track WM_LBUTTON* mouse messages as suggested in the other answer.
In response to WM_LBUTTONDOWN you set a global flag to true and start the timer. In response to WM_LBUTTONUP you set it to false and stop the timer. If the timer fires and the flag is true then perform your desired task.
If you're trying to implement this in WINAPI GUI application, here is your answer - write the first timestamp on WM_LBUTTONDOWN, write the second on WM_LBUTTONUP, and calculate the elapsed time you need. What is actually better - it will only catch messages that will come into YOUR application window, and won't catch other apps' key presses as you could do with GetAsyncKeyState.
UPDATE: Anyway, getting user-generated data(like clicks, key presses, etc) to work is way better using the standard windows message handling(as it is event-based, more natural to the programmer) instead of checking the state of an object once per a period of time - you can possibly miss the required event altogether. It looks like you're trying to solve the XY problem.
UPDATE2: Here is a nice tutorial of how to do it properly.

Prevent double click on MFC-Dialog button

i'm developing Autocad/Bricscad-Dialogs in MFC C++. Know i detected a bigger problem. There is a dialog which sets metadata for 'special' drawing objects. I update the data of every 'special' drawing object with this dialog (in a loop). So if you have ten 'special' drawing objects, the same dialog will open ten times (successively). Now i have the problem that the user sometimes make a double click on the "OK"-Button. But if this double click is fast enough, the "OK"-Button of the next instance of this dialog will clicked automatically. I tried a lot (for example disabling the button if it was clicked) but nothing solved my problem. Maybe someone of you have a good idea.
Best regards,
Simon
When you open a new dialog you can flush the message queue of mouse click messages before going into your normal message loop, e.g.:
MSG msg;
while (PeekMessage(&msg, hWndDlg, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE));
I try to extend the answer of Jonathan Potter.
When you open a new dialog and OnInitDIalog is called, just remove the mouse messages from the queue and wait for 1/10 of a second.
MSG msg;
DWORD dwStart = ::GetTickCount():
while (PeekMessage(&msg, hWndDlg, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE)!=0 ||
(::GetTickCount() - dwStart) < 100))
;
The trick with the PeekMessage will work, the problem is that you need to run the loop as long as a "double click" will take. If the clicks have a distance of 1/10th of a second you need to remove all mouse clicks for this period of time.
And also OnInitDialog is the correct position. You may extend this flush to all mouse messages WM_MOUSEFIRST/WM_MOUSELAST... to get all clicks.
The delay of 1/10 second when launching the next dialog isn't expensive or annoying.

Detect click on a blank item in a list control

In my mfc dialog based application, there is a CListCtrl. I need to disable a button when the user clicks on an empty item in the list control.I used NM_CLICK message and achieved this. But if the user drags the mouse out of list control area and releases the mouse this doesn't work. I found the reason that NM_CLICK will be called only on receiving button up message.Is there any other solution for this.
But if the user drags the mouse out of list control area and releases the mouse this doesn't work.
That is entirely by design, and you shouldn't want those clicks to "count". This is the only way that a user has of changing her mind in the middle of a click. It works like this:
Start to click on an object (or the empty space) in the list box control
Change your mind
While still holding down the mouse button (i.e., before committing your click), drag the mouse pointer outside of the bounds of the control
Think: Whew! That was a close call!
You'll notice that, in Windows, an action never happens until the mouse button is released (often called "MouseUp"). If this wasn't supported, there would be no way for the user to bail out early of an action, which is a critical feature of any user interface.
There are some feasible options.
In parent dialog, MouseUp Handler function can use for this.
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
By using point, you can check whether mouse releasing is occured CListCtrl.
If it is, you just disable the button.
Also, WindowFromPoint can be another option.
static CWnd* PASCAL WindowFromPoint(POINT point);
In such as a OnMouseMove, if you use this function, you can check the window is pointed by mouse.
Implement a LVN_ITEMCHANGED handler, and in that handler disable the button as soon as the selected item count is zero.
I found the solution for the issue. There is a message which can be handled if the user drags the mouse using left button namely LVN_BEGINDRAG.By handling this message in the OnBeginDrag function I update the button status.So the button gets updated as soon as the user tries to drag the mouse.The code is as below:
In the header add
afx_msg void OnBeginDrag( NMHDR* pNMHDR, LRESULT *pResult );
In the implementation add message map and corresponding function:
BEGIN_MESSAGE_MAP( .. )
ON_NOTIFY( LVN_BEGINDRAG, IDC_LIST1, OnBeginDrag )
END_MESSAGE_MAP
OnBeginDrag( .... )
{
Updatebutton();
}
It solves the issue. thank you all for the support.

Unhandled LButtonUp windows message in COleControl

I have a COleControl object in my project.
Inside this COleControl, I have a CRectTracker object.
I want to handle the windows message (event) of WM_LButtonUp. (when the user stops to press the left mouse button).
In my .h file I wrote:
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
In my .cpp file, in
BEGIN_MESSAGE_MAP(CMyControl, COleControl)
I added
ON_WM_LBUTTONUP()
Then I developed a method of
void CMyControl::OnLButtonUp(UINT nFlags, CPoint point)
I did the same thing for the windows message LButtonDown.
When I leave the left mouse button inside my control, method get handles and everything works fine.
The problem occurs when I leave the left mouse button when the mouse tracker is on the CRectTracker object. In this case, the mouse LButtonUp message does not get handled.
I tried to use Spy++ and I can see that the windows message WM_LButtonUp exists and occurs as expected. But it my code, it does not get handled (just in the case of mouse on the CRectTracker).
The LButtonDown event get handled successfully all the time, even when I press the mouse button while the mouse is on the CRectTracker.
What can be the problem with the LButtonUp message?
Thanks
That is just an inevitable side-effect of the way the tracker works. Once you click on the tracker or one of the sizing handles then MFC captures the mouse and starts a modal message loop. Which is going to pick off mouse-move and button-up messages to implement the tracking operation. That loop doesn't exit until the left button-up message is seen, the Escape key is seen or the capture is lost. Accordingly, your OnLButtonUp() function cannot run while that loop is active, the message was intercepted before it could be dispatched.
You'll need to do this differently, not relying on OnLButtonUp(). Hard to give specific advice since you didn't describe why you need it. The source code for the modal loop is in atlmfc/src/mfc/trckrect.cpp, CRectTracker::TrackHandle() if you need more insight.

"?" help button triggers WM_HELP _and_ WM_LBUTTONUP

I have a Windows application that registers one CALLBACK procedure that handles WM_HELP messages for the dialog, and one CALLBACK procedure that handles WM_LBUTTONUP messages for a custom button.
Now, when the user clicks the "?" button, then clicks the custom button, the help opens up as expected (on mouse down), BUT if the help window is not occluding the button, a WM_LBUTTONUP message is triggered as well for the custom button (on mouse up). This causes the button to trigger when the user was only asking for help.
Is there any way to stop the WM_LBUTTONUP message from being sent if the button press is for help?
EDIT: The custom button is implemented using a STATIC control. I believe this is because it needs to have an image and no border. So, it does not send BN_CLICKED notifications. In fact, it does not seem to trigger WM_COMMAND in the parent at all.
Thanks
This is normal. Be sure to use the button's BN_CLICKED notification to see the difference. Generated when the user clicks the button, not generated when the user uses the help cursor. The button still sees the normal button up/down messages so that's not a good trigger to detect a click. Extra bonus is that the button can now also be clicked with the keyboard (space bar).
A good class library takes care of these nasty little details.
A better way would be to create ? as a custom control with BS_CHECKBOX | BS_PUSHLIKE style and capture the mouse. After that you will get all the WM_LBUTTONDOWN message to this custom control and then you can use WindowFromPoint to get the window where the WM_LBUTTONDOWN happened and can send a custom notification to the parent window. The parent window can then show a the tooltip or open the help doc or discard it.
The advantage is, you create the control only once and you can use it in multiple places.
Okay, I fixed it by creating the custom button (static control) with the SS_NOTIFY style, then handling the STN_CLICKED notification in the WM_COMMAND message. (SS_NOTIFY causes WM_COMMAND to trigger in the parent when it is clicked.) This does not trigger when using the "?" button. Thanks!