Discussion:
Event handling and wxMenuBar
(too old to reply)
Jerome Breitenbach
2009-05-14 23:23:05 UTC
Permalink
Subject: Event handling and wxMenuBar

I'm fairly new to wxWidgets, though I have worked through several
examples and have been reading the wxWidgets documentation. In
particular, I've come across the following paragraph at
http://docs.wxwidgets.org/trunk/overview_events.html#overview_events_eventhandling.

To use an event table you must first decide in which class you wish
to handle the events. The only requirement imposed by wxWidgets is
that this class must derive from wxEvtHandler and so, considering
that wxWindow derives from it, any classes representing windows can
handle events. Simple events such as menu commands are usually
processed at the level of a top-level window containing the menu, so
let's suppose that you need to handle some events in MyFrame class
deriving from wxFrame.

Despite the remark about what is *usually* done, I decided to try to
handle events generated by a wxMenuBar within my menu bar class itself.
This seems more natural to me, since the events would be handled nearest
to where they are generated. Moreover, irrespective of whether this is
the "preferred" method, wxMenuBar does derive from wxWindow, and thus
also from wxEvtHandler.

However, all my attempts at this approach failed, whether using an event
table or wxEvtHandler::Connect() within my wxMenuBar subclass. After
much searching, I found the reason for this failure stated at
http://wiki.wxwindows.org/Events#wxMenuBar_Events:

A wxMenuBar doesn't send events to itself, but to its parent
frame. This might seem inconsistent, but it's actually convenient in
all common situations.

OK, even though I don't yet understand the convenience of doing so, I'll
now use the usual method for placing handlers of wxCommandEvent's
generated by wxMenuBar. But, I'm still left with several questions:

* Given the paragraph quoted above, how should I have been able to
conclude from the main wxWidgets docs
http://docs.wxwidgets.org/trunk/, http://docs.wxwidgets.org/stable/,
and http://www.wxwidgets.org/docs/book/ that wxMenuBar does not
receive the events it generates?

* Since wxMenuBar does not receive the events it generates, I see no
purpose to doing either of the following:
- placing an event table in a wxMenuBar subclass object
- having a wxMenuBar subclass object call Connect()
Accordingly, shouldn't any wxMenuBar subclass that does one of these
things fail to compile (thereby alerting the programmer of a
problem)?

* What other subclasses of wxEvtHandler don't receive the events they
generate? For example, the messages
http://groups.google.com/group/comp.soft-sys.wxwindows/browse_thread/thread/95e8ffcd9e5faba2/19270633c74d0e1,
seems to imply that this is the case for wxGrid. Without being
critical, it seems to me that such important information should be
stated--indeed, emphasized--in a prominent place, such as
http://docs.wxwidgets.org/trunk/overview_events.html.

* The above messages also observe that wxGrid contains a function
GetGridWindow(), and suggest calling GetGridWindow()->Connect(...)
from a wxGrid subclass. Why, then, doesn't wxMenuBar contain a
similar function like GetWindow() whereby one might call
GetWindow()->Connect(...) from a wxMenuBar subclass?

Thanks for the help,
Jerome
Vadim Zeitlin
2009-05-15 10:09:17 UTC
Permalink
On Thu, 14 May 2009 16:23:05 -0700 Jerome Breitenbach <***@calpoly.edu> wrote:

JB> Despite the remark about what is usually done, I decided to try to
JB> handle events generated by a wxMenuBar within my menu bar class itself.
JB> This seems more natural to me, since the events would be handled nearest
JB> to where they are generated.

Yes, this is a natural thing to expect to work and it should probably
count as a bug that it doesn't. But the fact is that currently this doesn't
work.

JB> Moreover, irrespective of whether this is the "preferred" method,
JB> wxMenuBar does derive from wxWindow, and thus also from wxEvtHandler.

The fact that wxMenuBar derives from a wxWindow is definitely a (design)
bug because it's not a window (just try to call any wxWindow methods on it,
most of it will do nothing at all while some will probably crash). Still,
it would make sense to derive it from wxEvtHandler and send the events
generated by its elements to the menu bar itself -- but, again, this isn't
how it works currently.

JB> However, all my attempts at this approach failed, whether using an event
JB> table or wxEvtHandler::Connect() within my wxMenuBar subclass. After
JB> much searching, I found the reason for this failure stated at
JB> http://wiki.wxwindows.org/Events#wxMenuBar_Events:
JB>
JB> A wxMenuBar doesn't send events to itself, but to its parent
JB> frame. This might seem inconsistent, but it's actually convenient in
JB> all common situations.
JB>
JB> OK, even though I don't yet understand the convenience of doing so,

It is convenient because most often the menu bar can't itself do much with
its events. It could handle "Help|About" item but that's about it -- for
anything else you usually do need the main frame.

JB> I'll now use the usual method for placing handlers of wxCommandEvent's
JB> generated by wxMenuBar.

This is the wisest course of action for now. The only alternative is to
modify wxWidgets to behave better.

JB> But, I'm still left with several questions:
JB>
JB> * Given the paragraph quoted above, how should I have been able to
JB> conclude from the main wxWidgets docs
JB> http://docs.wxwidgets.org/trunk/, http://docs.wxwidgets.org/stable/,
JB> and http://www.wxwidgets.org/docs/book/ that wxMenuBar does not
JB> receive the events it generates?

We do have

Remarks:
To respond to a menu selection, provide a handler for
EVT_MENU, in the frame that contains the menu bar.

at http://docs.wxwidgets.org/trunk/classwx_menu_bar.html. But maybe this is
not clear enough.

JB> * Since wxMenuBar does not receive the events it generates, I see no
JB> purpose to doing either of the following:
JB> - placing an event table in a wxMenuBar subclass object
JB> - having a wxMenuBar subclass object call Connect()
JB> Accordingly, shouldn't any wxMenuBar subclass that does one of these
JB> things fail to compile (thereby alerting the programmer of a
JB> problem)?

I agree that it should be either made to receive the events (which would
be consistent with wxMenu which does receive them) or stop deriving from
wxEvtHandler. And it shouldn't derive from wxWindow in any case.

JB> * What other subclasses of wxEvtHandler don't receive the events they
JB> generate?

wxMenuBar is the only example I can think of right now.

JB> For example, the messages
JB> http://groups.google.com/group/comp.soft-sys.wxwindows/browse_thread/thread/95e8ffcd9e5faba2/19270633c74d0e1,
JB> seems to imply that this is the case for wxGrid.

This is not quite the same, the events are generated by wxGrid children in
this case and so, as usual for non command events, their parent doesn't
receive them. It's still a common problem though.

JB> critical, it seems to me that such important information should be
JB> stated--indeed, emphasized--in a prominent place, such as
JB> http://docs.wxwidgets.org/trunk/overview_events.html.

Again, there is a note about this at
http://docs.wxwidgets.org/trunk/classwx_grid.html:

wxGrid is an empty parent window for 4 children representing the
column labels window (top), the row labels window (left), the
corner window (top left) and the main grid window. It may be
necessary to use these individual windows and not the wxGrid window
itself if you need to handle events for them (this can be done
using wxEvtHandler::Connect() or wxWindow::PushEventHandler()) or
do something else requiring the use of the correct window pointer.

but it might indeed not be quite prominent enough.

JB> * The above messages also observe that wxGrid contains a function
JB> GetGridWindow(), and suggest calling GetGridWindow()->Connect(...)
JB> from a wxGrid subclass. Why, then, doesn't wxMenuBar contain a
JB> similar function like GetWindow() whereby one might call
JB> GetWindow()->Connect(...) from a wxMenuBar subclass?

You can use wxMenuBar::GetFrame() but this is something really strange to
do as it's inside out compared to wxGrid case: there is nothing unusual
with connecting to child events in the (more central to the program design)
parent window but catching events for the main frame in one of its sub
elements seems strange. Although I guess there is nothing really preventing
you from doing this if for whatever reason you prefer to do it like that.

Good luck!
VZ
--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/
Loading...