Calling the event handler programmatically in an MFC application - c++

I am working on an MFC application (C++)
My checkbox has an event hander mapped to the ON_BN_CLICKED.
It works fine when the user check/uncheck the box, i.e. the event handler is called.
However, when I check the box programmatically: ((CButton *)this->GetDlgItem(x))-> ->SetCheck(1); the event handler is not called.
What should I do in order to call the event handler programmatically?

This is a normal behavior. The WM_COMMAND is sent when a "click" or "user entry" changed the button.
This is not contignous with child controls. Other child controls like an edit control also send a WM_COMMAND EN_CHANGE message when SetWindowText is executed by the program (the MFC blocks this message in a DoDataExchange).

Try to send BN_CLICKED:
this->SendMessage(WM_COMMAND,
MAKELONG(IDC_BUTTON1, BN_CLICKED),
((CButton *)this->GetDlgItem(x))->GetSafeHwnd());

Related

The CBN_SELCHANGE notification not works when i use the function ComboBox_SetCurSel

I have a ComboBox in a window and i want to execute a function after changing selected item.
When i change the selected item of the combobox by mouse or keyboard,
the CBN_SELCHANGE event in the window message WM_COMMAND works well and my function execute.
But if i use the function ComboBox_SetCurSel for changing the selected item ,it not works.
What window message WM_**** and combox notification do i use for processing the event changing selected item.
In general, when you programmatically manipulate a control, the corresponding notification is not sent to its parent. The notification only gets sent when the user manipulates the control.
So, when you call ComboBox_SetCurSel (which is a macro that performs the same task as sending the CB_SETCURSEL message), that programmatically changes the control's current selection and therefore does not send the CBN_SELCHANGE notification. However, CBN_SELCHANGE does get sent if the user changes the combobox's selection.
This is called out explicitly in the "Remarks" section of the documentation for CBN_SELCHANGE:
The CBN_SELCHANGE notification code is not sent when the current selection is set using the CB_SETCURSEL message.
To work around this, you can do one of two things:
Call your event-handler method directly. For example, in MFC, you would have the framework attach an OnCbnSelChange member function to handle the combobox's CBN_SELCHANGE notification. After your code that called ComboBox_SetCurSel, you would simply call that OnCbnSelChange member function manually:
ComboBox_SetCurSel(hwndComboBox, 0); // select 1st item
this->OnCbnSelChange(); // invoke the change event-handler
Your GUI framework undoubtedly has something similar.
Manually send the CBN_SELCHANGE notification to the control's parent. I don't really know why you would ever do this, because the default window procedure doesn't do anything interesting upon receipt of this notification; you would be much better off just calling your own handler directly.
::PostMessage(hwndParent,
WM_COMMAND,
MAKEWPARAM(IDC_COMBOBOX, CBN_SELCHANGE),
reinterpret_cast<LPARAM>(hwndComboBox);
Or, if you were doing this from a subclass of the combobox:
HWND hwndParent = ::GetAncestor(hwndComboBox, GA_PARENT);
int ctrlID = static_cast<int>(::GetWindowLongPtr(hwndComboBox, GWLP_ID));
::PostMessage(hwndParent,
WM_COMMAND,
MAKEWPARAM(ctrlID, CBN_SELCHANGE),
reinterpret_cast<LPARAM>(hwndComboBox));

MFC Message flow for controls?

In MFC, suppose I have a dialog box, and in this box, it has a child CListCtrl, then I use mouse to click this CListCtrl, we know that eventually an WM_LBUTTONDOWN message is sent to CListCtrl. My question is: How does this WM_LBUTTONDOWN message get there?
Two possibilities:
Dialog box first gets this WM_LBUTTONDOWN message , and it finds that mouse click occurs in its child window, then it forwards this message to CListCtrl.
CListCtrl first gets this WM_LBUTTONDOWN message, it can process this message, and if it doesn't care it will forward this message to parent window, i.e. dialog box for further processing.
Which one is true?
Thanks.
Input messages are never sent to a window. They are posted to the message queue associated with a window, waiting to be retrieved through one of the message retrieval functions (GetMessage, PeekMessage, etc.).
Depending on whether the dialog box is modal or modeless, messages are retrieved by the nested modal loop (for modal dialogs) or the application's message loop. The message is then passed on to DispatchMessage, to find the recipient (starting from the topmost visible window under the mouse pointer, that is neither disabled nor transparent), and call into the associated window's window procedure. The window procedure can decide, whether it handles the message or not. A window procedure typically calls DefWindowProc to perform default processing, if it doesn't handle a message.
To summarize: The application's message loop (or the nested modal message loop) gets to see the message first, and instructs the window manager to deliver the message to the respective recipient.
A thorough description on Windows message processing is available at About Messages and Message Queues. The description is specific to the Windows API. Since MFC is just a wrapper around the Windows API, the contents apply to MFC as well, even though some of the concepts are hidden in a typical MFC application.

Are DialogBox messages sent to a custom message loop?

I have an application that currently has a message loop. If I were to create a modal dialog box with the DialogBox method would the current message loop receive messages from the dialog as well or would they be withheld by the runtime?
DialogBox creates its own message loop so your message loop will not run. From the documentation:
The function displays the dialog box (regardless of whether the
template specifies the WS_VISIBLE style), disables the owner window,
and starts its own message loop to retrieve and dispatch messages for
the dialog box.
Your existing message loop will not receive the messages for the dialog box. All messages for the dialog would be received by the DLGPROC method that you're passing as the last parameter to the DialogBox function.

How I can get a focus message in MFC?

I have a dialog box with some CListCtrl. I want that when I click on one of them, receive killfocus or setfocus message.
How I can get it?
The CListCtrl class wraps the Win32 ListView control. That control communicates with its parent (your dialog) via WM_NOTIFY messages.
So you can process WM_NOTIFY messages from your list control in your dialog class. Use the Properties window to create an OnChildNotify handler function and write a switch statement that handles the notification message(s) of interest.
The possible notification messages are listed here in the Windows SDK documentation.

"?" 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!