Reputation: 39858
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?
Upvotes: 3
Views: 840
Reputation: 25187
Head Geek's solution didn't work for me for wxWidgets 3.0.2, but I found a different one: Use Bind
to temporarily register a wxEVT_MENU_HIGHLIGHT
event handler on the wxFrame
containing the clicked control. Full example:
class FunctionMenuWindow : public wxWindow
{
public:
int option;
FunctionMenuWindow(wxWindow *parent) : wxWindow(parent, -1), option(0), mPushed(false)
{
this ->Bind(wxEVT_MENU , &FunctionMenuWindow::OnMenu , this, wxID_ANY);
theMainWin->Bind(wxEVT_MENU_OPEN , &FunctionMenuWindow::OnOpen , this, wxID_ANY);
theMainWin->Bind(wxEVT_MENU_CLOSE , &FunctionMenuWindow::OnClose , this, wxID_ANY);
theMainWin->Bind(wxEVT_MENU_HIGHLIGHT, &FunctionMenuWindow::OnHighlight, this, wxID_ANY);
}
~FunctionMenuWindow()
{
theMainWin->Unbind(wxEVT_MENU_OPEN , &FunctionMenuWindow::OnOpen , this, wxID_ANY);
theMainWin->Unbind(wxEVT_MENU_CLOSE , &FunctionMenuWindow::OnClose , this, wxID_ANY);
theMainWin->Unbind(wxEVT_MENU_HIGHLIGHT, &FunctionMenuWindow::OnHighlight, this, wxID_ANY);
}
private:
void OnMenu(wxCommandEvent& event)
{
option = event.GetId();
}
void OnOpen(wxMenuEvent &evt)
{
this->mMenu = evt.GetMenu();
if (!mPushed)
{
theMainWin->GetStatusBar()->PushStatusText(wxString());
mPushed = true;
}
}
void OnClose(wxMenuEvent &evt)
{
if (mPushed)
{
theMainWin->GetStatusBar()->PopStatusText();
mPushed = false;
}
}
const wxString GetHelpString(wxMenuEvent &evt)
{
if (evt.GetMenuId() < 0)
return wxString();
else
return mMenu->GetHelpString(evt.GetMenuId());
}
void OnHighlight(wxMenuEvent &evt)
{
if (mPushed)
theMainWin->GetStatusBar()->SetStatusText(GetHelpString(evt));
else
{
theMainWin->GetStatusBar()->PushStatusText(GetHelpString(evt));
mPushed = true;
}
}
bool mPushed;
wxMenu* mMenu;
};
///////////////////////////////////////////////////////////////////
void ShowMenu()
{
FunctionMenuWindow funcWindow(theMainWin);
wxMenu *menu = new wxMenu;
// ... set up wxMenu ...
funcWindow.PopupMenu(menu);
switch(funcWindow.option)
{
// ... switch by wxID as usual ...
}
}
Upvotes: 0
Reputation: 39858
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.
Upvotes: 1