Search code examples
wxwidgets

How do I show the help strings for wxWidgets popup menus?


wxWidgets apps show the help strings for normal menu items in the status bar of the main window. Unfortunately, it doesn't seem to show them for menus invoked with the wxWindow::PopupMenu command, and I need it to.

I've tried adding an EVT_MENU_HIGHLIGHT_ALL handler to the parent window, but it's not getting called.

There's got to be some way to handle or redirect the messages to show the help text. What am I missing?


Solution

  • I tried invoking it via the wxFrame instead of the current window (a wxListCtrl). That helped, but not much: it would clear the status bar when the mouse moved over a popup menu item, but wouldn't show the help text for it.

    When I dug into the wxWidgets source code, I discovered the reason: my popup menu's items weren't on the menu bar. wxWidgets sends the ID of the menu item to the menu bar to fetch the text, which obviously fails in this case.

    It took some doing, but I figured out a way around the problem:

    ////////////////////////////////////////////////////////////////////////////
    // In a header file...
    
    class PopupMenu: public wxMenu {
        public: //
        PopupMenu(): mPushed(false) { }
    
        void OnOpen(wxMenuEvent &evt);
        void OnClose(wxMenuEvent &evt);
        void OnShowMenuHelp(wxMenuEvent &evt);
    
        private: //
        bool mPushed;
    
        DECLARE_EVENT_TABLE()
    };
    
    ////////////////////////////////////////////////////////////////////////////
    // In a cpp file...
    
    BEGIN_EVENT_TABLE(PopupMenu, wxMenu)
        EVT_MENU_OPEN(PopupMenu::OnOpen)
        EVT_MENU_CLOSE(PopupMenu::OnClose)
        EVT_MENU_HIGHLIGHT(wxID_ANY, PopupMenu::OnShowMenuHelp)
    END_EVENT_TABLE()
    
    void PopupMenu::OnOpen(wxMenuEvent &evt) {
        if (!mPushed) {
            // Clear it
            findStatusBar()->PushStatusText(wxString());
            mPushed = true;
        }
    }
    
    void PopupMenu::OnClose(wxMenuEvent &evt) {
        if (mPushed) {
            findStatusBar()->PopStatusText();
            mPushed = false;
        }
    }
    
    void PopupMenu::OnShowMenuHelp(wxMenuEvent &evt) {
        if (mPushed) {
            findStatusBar()->SetStatusText(GetHelpString(evt.GetMenuId()));
        } else {
            findStatusBar()->PushStatusText(GetHelpString(evt.GetMenuId()));
            mPushed = true;
        }
    }
    

    (findStatusBar is a convenience function that locates the program's frame window and calls GetStatusBar on it.)

    Now I just derive a class from PopupMenu for any popups that I need. The results are perfect.

    There may be an easier way around this problem, but without putting the popup's items on the menu bar, I wasn't able to find it.