I have a CDialogEx Class called Properties in which I handle the ON_COMMAND message. Now, ON_COMMAND should get called when I click the menu item ID_EDIT_PROPERTIES (as a submenu from main menu). The event handler wizard wrote that code for me, but when I start the Application the menu item remains grayed out. I've tried to manually activate it by calling EnableMenuItem when ON_UPDATE_COMMAND_UI happens, but to no avail.
Any help would be greatly appreciated.
You just need to understand how menu items enabling/disabling is handled:
If there is neither ON_COMMAND nor ON_UPDATE_COMMAND_UI handler the item is disabled.
If there exists no ON_UPDATE_COMMAND_UI handler but there is an ON_COMMAND one in the currently active document or view (or even the "mainframe"), the item is enabled.
If there exists a ON_UPDATE_COMMAND_UI handler, en-/disabling the item is determined by the handler (pCmdUI->Enable(bEnableState)).
Also keep in mind that:
You may not call EnableMenuItem() yourself, instead call pCmdUI->Enable(bEnableState) in an ON_UPDATE_COMMAND_UI handler. This affects not only the menu item, but any other "command"-type item (with the same ID), eg main menu, context menu, toolbar or rebar button.
Where to put the handler, is a matter of application design and depends on the data you are processing or representing. It can be put in the mainframe class (if it depends on some "global" data or setting), in the document class (if it depends on or changes some data or setting in the document - possibly affecting all views), or in the view class(-es) (depending on or affecting the current view only).
In your case, if I understand correctly, the item is disabled because the handler is in the CDialogEx-derived class, but no instance of this class has been created yet, ie there exists no ON_COMMAND handler for your ID_EDIT_PROPERTIES command.
Per m_bAutoMenuEnable, When this data member is enabled (which is the default), menu items that do not have ON_UPDATE_COMMAND_UI or ON_COMMAND handlers will be automatically disabled when the user pulls down a menu.
I admit that I don't know ii it is different for CDialogEx, But for CDialog I found that the UPDATE_COMMAND_UI didn't ever work unless I handled the WM_KICKIDLE event.
In your OnKickIdle event handler make a call to:
CWnd::UpdateDialogControls
There is a short tutorial on it here.
Forgive me if CDialogEx supercedes this information and I will remove the answer.
Related
I'm trying to add drag and drop functionality to a control on a property page which is programmatically "wrapped" inside an MFC dialog at runtime. This "wrapping" involves instantiating the property page as a member of the dialog, and then resizing it and positioning it to the dimensions of a picture control which is on the dialog in the .rc file. I'm not sure why things were done this way, other than to maybe standardise the appearance of property pages in the app, but in any case I end up with this complicated hierarchy of windows, a control inside a property page inside a picture control inside a dialog.
The control which I want to accept dragged files has DragAcceptFiles invoked on it, but I think the WM_DROPFILES message for the control is being discarded before it reaches the control, because one of the parent windows doesn't accept dragged files. I considered calling DragAcceptFiles on all the parents, and passing WM_DROPFILES down the chain of windows, but I don't want to do that because they won't have handlers to accept the files, and will show the icon indicating files can be dropped on them regardless.
Any help on figuring out how to get the WM_DROPFILES message to my control would be much appreciated.
At the parent level, implement an override for virtual CDialog::PreTranslateMessage(MSG* pMsg)
This gives you a chance to see the WM_DROPFILES message and redirect them to a handler in the property page.
I figured this out in the end by calling CWnd::BringWindowToTop() on both the control I wanted to drag files onto, and also the dialog that the control was on.
I have a settings dialog that has some settings that require another dialog to fully configure. My window shows a preview of the data as it's being tweaked by these settings. Upon clicking on the configuration button I launch another modal dialog with some knobs to twist to fine tune the particular setting.
I wish to send the result of the twisting of the knobs on the child dialog back to the parent dialog so that it can show the new preview data as the knobs on the child are being played with. The way I imagine it is I have a "refresh preview" function in the parent that is called after modification of it's data preview member variables. The question is, how do I do this? How can I access getters/setters from the parent dialog as a modal child dialog? If I do access them will the preview change or will it be blocked because of the modality of the child?
Thank you!
In Qt world, it is generally encouraged to exploit the Signal/Slot mechanism. In short, classes can send signals when something changes within that class. And slots can receive such signals provided we notified the receiving classes appropriately.
Let us look at how we can do it for our present case.
In our settings dialog constructor, we include this code (assumption is that you display the "another" dialog when a button is pressed):
Dialog *dialog = new Dialog();
connect(dialog->dial(), &QDial::valueChanged, this, &QSettingsDialog::changeTemp);
Code walkthrough:
Our QDialog has been constructed with a QDial object, dial. We access that member pointer with dialog->dial().
We tie the signal that emits the value changed on the dial to the slot called changeTemp that receives the value changed and sets the display widget on the settings dialog (parent) accordingly.
The changeTemp method might be like so:
void QSettingsDialog::changeTemp(int val)
{
lineEdit->setText(QString::number(val));
}
Notes:
You need to declare the Q_OBJECT macro on all classes that need to implement Signals and slot. In this case, both the settings dialog and the child dialog.
The above signal/slot signature is the new Qt5 signature. If you are on a version below 5.0, the signature is different. Refer to the docs.
If I click anywhere on the dialog window, like in the "background", or on a Static Text, the function OnLButtonDown() is fired. But if I click a ListBox/EditBox/Combo/Calendar/Checkbox etc is not fired.
I thought that because these have control variables atached to it, and the Static Text don't. But adding a new Listbox to my Dialog and testing, I see that it doesn't fire either, so now I am confused...
I added OnLButtonDown() with the Class Wizard, it appears in:
BEGIN_MESSAGE_MAP(CMFCTesting2Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
// other handlers, etc
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
My function:
void CMFCTesting2Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
AfxMessageBox(CString("BUTTON DOWN"));
CDialogEx::OnLButtonDown(nFlags, point);
}
I tried calling CDialogEx:: ... before AfxMessageBox... but same result.
The CListBox item, has the Notify option set to True, as I seen some advices in other posts.
I suspect that the WM notification message is captured somehow by the ListBox, and not sent "forward" to my CMFCTesting2Dlg, but I understood that this should happen with the Notify option set to True, on the ListBox, no? (well, obviously, not...)
Sorry, I am new to dealing with WM in MFC.
BTW, I use Visual Studio 2010 Ultimate, and this is a Visual C++ - MFC- MFC Application - Dialog Based project.
How can I capture this mouse down event if clicked on a listbox / combo / etc?
On the LONG STORY, I am actually trying to accomplish this issue:
I have two listboxes (lets say), and I want to scroll them synchronously, when user scrolls one of them, others must scroll the same (or update in the next moment). And I thought of using on mouse down to track the position of every Listbox (with the GetTopIndex), and on mouse up, to GetTopIndex again and compare with the previous ones. If a change was made, then a listbox was scrolled and then update all listboxes with SetTopIndex. The unfriendly solution for the user, but simpler for me, would be clicking a button that does this verification / update, but its not elegant at all, and it can only set them at the same level, but can't determine which one was scrolled last time. This automatically scrolling of the listboxes should be made just for displaying, it is not important the selections in the listboxes. I tried using the Message Type in the Add Event Handler for the Listbox, but none that are displayed work for my problem, KillFocus and SetFocus, are not fired if the scroll-bar is dragged, only if an item in the listbox is clicked... and I didn't succeed on the others message type either, from the Add Event Handler.
Once a window handles a message, it stops being sent to the other windows beneath it. A static window doesn't handle a mouse down, so it goes to the dialog. The other controls all handle it in some fashion (setting focus at least) so it never gets to the dialog.
You can override the OnLButtonDown handler in each of the controls to do something else once they've finished their default handling in the base class. You might also get to see the message in the PreTranslateMessage method of the dialog.
As far as getting the List Controls to sync scrolling goes, your best bet would be to intercept WM_VSCROLL by subclassing CListCtrl or perhaps by PreTranslateMessage, and then calling SetScrollInfo on the other list. If the number of items in the lists are the same, it should be fairly simple.
I've created a simple Dialog box with a few controls (edit, text, etc) and saved
it to the resource folder in GME/GME.rc/Dialog
I added an auto-gen'd event handler which created a new class (Class.cpp
for the purposes of this example) Note: the Class::Class(CWnd *pParent) :
CDialogEx(Class::IDD, pParent) constructor is empty, I'm not sure if that's
relevant but I don't think it is..
There's a MESSAGE_MAP COMMAND(menu_item_id, &class::member_function())
invocation within the Class.cpp was auto-generated. It's wrapped in the
standard BEGIN_MESSAGE_MAP macro stuff.
However: when the menu item is clicked, the item remains gray. The
properties for "enabled=true" and "gray=false" are both properly
configured. So, I assume this is error is due to the message handler isnt
registered.
Any help would be appreciated.
Without code, it's pretty darn hard to help. Are you sure you put the message handler for the menu id in either a CView, CFrame, CDocument, or CWinApp derived class? If you put the menu handler in your dialog class, it's not going to do you much good.
Dialogs do not contain the code to run through the list of ON_UPDATE_COMMAND_UI handlers that MFC uses to enable menu items. Ordinarily this is handled by CFrameWnd for example. Try calling UpdateDialogControls in your OnInitDialog function.
I see that your code is also missing the ON_UPDATE_COMMAND_UI macro for the menu item, even though the handler it would reference was created for you.
You add menu item handlers to the window that has the menu, which is usually the CMainFrame. Copy the message map and handler to the CMainFrame and see if that helps. I'm not sure what you're trying to do here - I assume you want to display 'Class' (maybe better to edit your post to call this 'ExampleDialog' or something...) when the menu item is clicked, right? Or did you somehow add a menu to your CDialogEx-derived class? If the last, I guess this is what Mark is referring to - 'how are you displaying the menu'? How are you manually adding a menu to your dialog?
I am trying to upgrade my MFC MDI application to use the new MFC Feature Pack.
I converted the CToolbar to CMFCToolBar. Now I am trying to disable one item in the toolbar under certain conditions. I listened to the ON_UPDATE_COMMAND_UI message of the item's ID and disabled the item by writing the following:
pCmdUI->Enable(FALSE);
This works perfectly only if the ON_UPDATE_COMMAND_UI message was handled in the CView object but not if handled in the CMFCToolbar derived class.
If there a way to disable an item from the toolbar class itself?
The Toolbar is not part of the command routing in MFC. So it will never get the command and update command UI messages. You can see the command routing in detail here: MFC Command Routing
You could overwrite the OnCmdMsg() method in one of the objects which gets the command messages (as you can see in the link above) and pass the message on to the Toolbar.