Harmonize wxMenuEvent handling between all major ports.

Send these events to the menu itself first, then to the menu bar containing
it or the window invoking it if it's a popup menu and, finally, to the top
level window in all of wxGTK, wxMSW and wxOSX.

In particular, this ensures that help strings are now shown in the parent MDI
frame status bar by default, even when the menus are attached to the client
MDI frame or shown as popup menus.

At the implementation level, this logic is now encapsulated in a new static
wxMenu::ProcessMenuEvent() method which can be easily modified and reused in
other ports.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@78230 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-12-05 22:17:58 +00:00
parent 62763ad541
commit 2d20e3fc51
7 changed files with 79 additions and 53 deletions

View File

@@ -93,6 +93,7 @@ All (GUI):
- Add wxUIActionSimulator::Select(). - Add wxUIActionSimulator::Select().
- Add wxOwnerDrawnComboBox::Is{List,Text}Empty() methods. - Add wxOwnerDrawnComboBox::Is{List,Text}Empty() methods.
- Fix creating/removing mode buttons in wxPG manager (Artur Wieczorek). - Fix creating/removing mode buttons in wxPG manager (Artur Wieczorek).
- Harmonize wxMenuEvent handling between all major ports.
wxGTK: wxGTK:

View File

@@ -309,6 +309,13 @@ public:
// the checked parameter may have boolean value or -1 for uncheckable items // the checked parameter may have boolean value or -1 for uncheckable items
bool SendEvent(int itemid, int checked = -1); bool SendEvent(int itemid, int checked = -1);
// called to dispatch a wxMenuEvent to the right recipients, menu pointer
// can be NULL if we failed to find the associated menu (this happens at
// least in wxMSW for the events from the system menus)
static
bool ProcessMenuEvent(wxMenu* menu, wxMenuEvent& event, wxWindow* win);
// compatibility: these functions are deprecated, use the new ones instead // compatibility: these functions are deprecated, use the new ones instead
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@@ -390,8 +397,8 @@ protected:
private: private:
// Helper of SendEvent(): sends the event to its intended recipients, // Common part of SendEvent() and ProcessMenuEvent(): sends the event to
// returns true if it was processed. // its intended recipients, returns true if it was processed.
static bool DoProcessEvent(wxMenuBase* menu, wxEvent& event, wxWindow* win); static bool DoProcessEvent(wxMenuBase* menu, wxEvent& event, wxWindow* win);
wxDECLARE_NO_COPY_CLASS(wxMenuBase); wxDECLARE_NO_COPY_CLASS(wxMenuBase);

View File

@@ -4107,8 +4107,24 @@ public:
these do not include menu command events, which are these do not include menu command events, which are
handled using wxCommandEvent objects. handled using wxCommandEvent objects.
The default handler for @c wxEVT_MENU_HIGHLIGHT displays help Events of this class are generated by both menus that are part of a
text in the first field of the status bar. wxMenuBar, attached to wxFrame, and popup menus shown by
wxWindow::PopupMenu(). They are sent to the following objects until one of
them handles the event:
-# The menu object itself, as returned by GetMenu(), if any.
-# The wxMenuBar to which this menu is attached, if any.
-# The window associated with the menu, e.g. the one calling
PopupMenu() for the popup menus.
-# The top level parent of that window if it's different from the
window itself.
This is similar to command events generated by the menu items, but, unlike
them, wxMenuEvent are only sent to the window itself and its top level
parent but not any intermediate windows in the hierarchy.
The default handler for @c wxEVT_MENU_HIGHLIGHT in wxFrame displays help
text in the status bar, see wxFrame::SetStatusBarPane().
@beginEventTable{wxMenuEvent} @beginEventTable{wxMenuEvent}
@event{EVT_MENU_OPEN(func)} @event{EVT_MENU_OPEN(func)}

View File

@@ -651,28 +651,39 @@ bool wxMenuBase::DoProcessEvent(wxMenuBase* menu, wxEvent& event, wxWindow* win)
{ {
event.SetEventObject(menu); event.SetEventObject(menu);
wxMenuBar* const mb = menu->GetMenuBar(); if ( menu )
// Try the menu's event handler first
wxEvtHandler *handler = menu->GetEventHandler();
if ( handler )
{ {
// Indicate to the event processing code that we're going to pass this wxMenuBar* const mb = menu->GetMenuBar();
// event to another handler if it's not processed here to prevent it
// from passing the event to wxTheApp: this will be done below if we do
// have the associated window.
if ( win || mb )
event.SetWillBeProcessedAgain();
if ( handler->SafelyProcessEvent(event) ) // Try the menu's event handler first
return true; wxEvtHandler *handler = menu->GetEventHandler();
if ( handler )
{
// Indicate to the event processing code that we're going to pass
// this event to another handler if it's not processed here to
// prevent it from passing the event to wxTheApp: this will be done
// below if we do have the associated window.
if ( win || mb )
event.SetWillBeProcessedAgain();
if ( handler->SafelyProcessEvent(event) )
return true;
}
// If this menu is part of the menu bar, try the event there. this
if ( mb )
{
if ( mb->HandleWindowEvent(event) )
return true;
// If this already propagated it upwards to the window containing
// the menu bar, we don't have to handle it in this window again
// below.
if ( event.ShouldPropagate() )
return false;
}
} }
// If this menu is part of the menu bar, process the event there: this will
// also propagate it upwards to the window containing the menu bar.
if ( mb )
return mb->HandleWindowEvent(event);
// Try the window the menu was popped up from. // Try the window the menu was popped up from.
if ( win ) if ( win )
return win->HandleWindowEvent(event); return win->HandleWindowEvent(event);
@@ -681,6 +692,24 @@ bool wxMenuBase::DoProcessEvent(wxMenuBase* menu, wxEvent& event, wxWindow* win)
return false; return false;
} }
/* static */
bool
wxMenuBase::ProcessMenuEvent(wxMenu* menu, wxMenuEvent& event, wxWindow* win)
{
// Try to process the event in the usual places first.
if ( DoProcessEvent(menu, event, win) )
return true;
// But the menu events should also reach the TLW parent if they were not
// processed before so, as it's not a command event and hence doesn't
// bubble up by default, send it there explicitly if not done yet.
wxWindow* const tlw = wxGetTopLevelParent(win);
if ( tlw != win && tlw->HandleWindowEvent(event) )
return true;
return false;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxMenu attaching/detaching to/from menu bar // wxMenu attaching/detaching to/from menu bar
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -74,16 +74,7 @@ static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event)
if ( !IsMenuEventAllowed(menu) ) if ( !IsMenuEventAllowed(menu) )
return; return;
event.SetEventObject( menu ); wxMenu::ProcessMenuEvent(menu, event, menu->GetWindow());
wxEvtHandler* handler = menu->GetEventHandler();
if (handler && handler->SafelyProcessEvent(event))
return;
wxWindow *win = menu->GetWindow();
wxCHECK_RET( win, "event for a menu without associated window?" );
win->HandleWindowEvent( event );
} }
// Return the top level menu containing this menu (possibly this menu itself). // Return the top level menu containing this menu (possibly this menu itself).

View File

@@ -2269,9 +2269,7 @@ wxWindowMSW::HandleMenuSelect(WXWORD nItem, WXWORD flags, WXHMENU hMenu)
item = wxID_NONE; item = wxID_NONE;
wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item); wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item);
event.SetEventObject(this); if ( wxMenu::ProcessMenuEvent(MSWFindMenuFromHMENU(hMenu), event, this) )
if ( HandleWindowEvent(event) )
return true; return true;
// by default, i.e. if the event wasn't handled above, clear the status bar // by default, i.e. if the event wasn't handled above, clear the status bar
@@ -2291,9 +2289,8 @@ bool
wxWindowMSW::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu) wxWindowMSW::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu)
{ {
wxMenuEvent event(evtType, menu && !menu->IsAttached() ? wxID_ANY : 0, menu); wxMenuEvent event(evtType, menu && !menu->IsAttached() ? wxID_ANY : 0, menu);
event.SetEventObject(menu);
return HandleWindowEvent(event); return wxMenu::ProcessMenuEvent(menu, event, this);
} }
bool wxWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu) bool wxWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu)

View File

@@ -555,22 +555,7 @@ void wxMenu::HandleMenuClosed()
bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent) bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
{ {
wxevent.SetEventObject(this); return ProcessMenuEvent(this, wxevent, GetWindow());
wxEvtHandler* handler = GetEventHandler();
if (handler && handler->ProcessEvent(wxevent))
{
return true;
}
else
{
wxWindow *win = GetWindow();
if (win)
{
if ( win->HandleWindowEvent(wxevent) )
return true;
}
}
return false;
} }
// Menu Bar // Menu Bar