![]() |
|
QA: How to enable update command UI mechanism in dialogs?
By Alexander Shargin, June 19, 2003.
QuestionI am writing an MFC-based application. I added a menu and/or a toolbar to one of my dialogs. I also wrote ON_UPDATE_COMMAND_UI handlers for it. But they are never called. How can I fix this? AnswerUpdate command UI mechanism is a convenient way to update state of toolbars and menus in MFC. However, this mechanism is implemented in CFrameWnd class. This means that it works in the main window based on CFrameWnd but doesn't work in other windows. In order to use it in a dialog or any other window, you basically have to implement it from scratch using the code from CFrameWnd as an example. In this article I will show you how to do this. Updating popup menusIn Windows, popup menus are initialized in response to WM_INITMENUPOPUP message. CFrameWnd has a handler for this message called OnInitMenuPopup. This is where MFC calls your ON_UPDATE_COMMAND_UI handlers for menu items. So you should add a OnInitMenuPopup handler to your dialog and copy all the code from CFrameWnd handler. Note: by default ClassWizard doesn't allow you to add WM_INITMENUPOPUP handelr to a dialog class. To change this behaviour, open ClassWizard, choose your dialog class from Class name combo box, go to Class Info tab and choose Message filter: Window. Here is how OnInitMenuPopup handler can look (it is just a slightly modified version of CFrameWnd::OnInitMenuPopup). Updating toolbarsEach command bar is responsible for updating its controls in response to WM_IDLEUPDATECMDUI message. MFC sends this message to the main frame and all of its descendants in the idle time (this is done in CWinApp::OnIdle handler). Then this message is handled in CControlBar class which is the base calss for all bar classes in MFC. Actual updating is performed in OnUpdateCmdUI method which is virtual and is overriden in every CControlBar-derived class. So to update your dialog's toolbar, all you need is to call its OnUpdateCmdUI method: Note: as you can see, this pointer is cast to CFrameWnd*. This is safe since OnUpdateCmdUI doesn't use any CFrameWnd-specific features through this pointer. The problem is, where to call this method. In desktop version of MFC all modal windows (including dialogs) can use built-in idle mechanism: when there are no more messages in the message queue, CWnd::RunModalLoop sends a special WM_KICKIDLE message (#defined in afxpriv.h) to the modal window. You can handle this message and perform any idle-time work in your handler. However, on CE this mechanism is removed from modal loop with the following comment: So you need to reinvent the wheel once again and implement idle mechanism yourself. When it comes to modifying message loop behaviour, your hook to the message loop is CWnd::PreTranslateMessage. In this method you can check if no more messages are waiting in the queue (use PeekMessage for this). If the queue is empty, it is time to perform updating of your toolbar. Here is what your PreTranslateMessage override may look like. I use CWinThread::IsIdleMessage to determine if a message should trigger idle processing. This function doesn't work correctly on Pocket PC 2002 devices (I described this problem here). To fix this, additional check if performed in the if statement. DialogUpdateCmdUI demo project illustrates how these techniques are used in a real application. SampleYou can download a sample application DialogUpdateCmdUI.zip (19 Kb). Related resources:
DiscussDiscuss this article. Here you can write your comments and read comments of other developers. |
|||||||||||||||||||||