lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Event handling modernization (was: a slight access violation)


From: Vadim Zeitlin
Subject: [lmi] Event handling modernization (was: a slight access violation)
Date: Sun, 30 Nov 2014 02:04:56 +0100

On Sun, 09 Nov 2014 20:35:34 +0000 Greg Chicares <address@hidden> wrote:

GC> On 2014-10-27 20:53Z, Vadim Zeitlin wrote:
GC> > 
GC> 
GC> [...the application receives menu events, not the MDI frame; and
GC> then, when the application becomes SkeletonTest, and the GUI test
GC> receives lmi's menu events, surprising things may happen...]
GC> 
GC> >  But then, personally, I wouldn't be doing this at wxApp level at all
GC> > anyhow, but rather in wxFrame containing the menus to be updated or the
GC> > commands to be processed, because I think that it is best to handle the
GC> > events as locally as possible.
GC> 
GC> That makes sense. When I ported old code from OWL to wx, I saw
GC> macros in wx samples that looked very much like OWL, so I used
GC> them with wx too, e.g.:
GC> 
GC>   BEGIN_EVENT_TABLE(Skeleton, wxApp)
GC>     EVT_MENU(wxID_ABOUT, Skeleton::UponAbout)
GC> 
GC> (I always had a sense that Julian must have known OWL very well.)

 Actually I strongly suspect that Julian knew MFC (as wx v1 was too similar
to it for this to be a simple coincidence) and I'm all but certain that MFC
programmers knew OWL (as it was quite like Microsoft to take an existing
product, study it, then make a clone of it and destroy the original using
better (if not necessarily legal) marketing strategy). But I won't go into
the details as I have been told (several times) that, incredible as it may
seem, not everyone is interested in software archaeology.


GC> However, I looked back at my old OWL code, and found:
GC> 
GC>   DEFINE_RESPONSE_TABLE1(PMMDIClient, TMDIClient)
GC>     EV_COMMAND(CM_FILEPRINT, CmFilePrint),
GC>     EV_COMMAND_ENABLE(CM_FILEPRINT, CmPrintEnable),
GC>   END_RESPONSE_TABLE;
GC> 
GC> Thus, I was certainly handling menu events at a lower level then,
GC> which is your point above; and I agree that it's a better idea
GC> now. How, specifically, would you recommend changing lmi?
GC>
GC> Derive a new MDI frame (or MDI client) class from a wx base?

 MDI client doesn't exist in wx public API because this is something too
Windows-specific and doesn't have any reasonable equivalent under other
platforms. So I'd indeed recommend doing it at MDI parent frame level.

 For completeness, here are the different levels at which this event could
be handled:

1. In a custom wxMenu subclass that we'd use for the "Window" menu. This is
   actually probably the best variant, abstractly speaking, as it ensures
   that the event is handled as close to its source as possible and
   entirely encapsulates the responsibility for enabling the menu items in
   the menu itself, which is nice. But the menu would need to "reach out"
   into the containing frame to get the total number of children, which
   somewhat spoils this encapsulation and it's relatively unusual to have
   event handling logic in the menu itself.

2. At child frame level. This is in the middle between (1) and (4) and so
   doesn't seem appealing. In practice, the only nice thing about this
   solution would have been that we could do it at DocMDIChildFrameEx
   level, i.e. avoid introducing a new wxDocMDIParentFrame-derived class
   just for this. But, as explained below, we can do this anyhow with
   dynamic event binding, so if you're fine with using it, this advantage
   is negated.

3. At parent frame menu bar level. I can't see any reason to prefer this
   to (4), so I mention this just for completeness.

4. At parent frame level. This does fully encapsulate this logic as well
   and it does seem logical to do something depending on the number of
   children of a frame in this frame itself.

 All of the above would work, but the last one seems the best to me, and so
this is what the first attached patch
(0001-Handle-only-the-menu-open-events-for-the-main-frame-.patch) does.

GC> I believe you prefer Connect() over event-table macros; would
GC> you recommend that sort of change, too?

 Yes, absolutely. With Bind() (which is a modern replacement for Connect()
whose only advantage compared to Bind() was that it could work even with
the pre C++98 MSVC 6 compiler), this code can remain in the same Skeleton
method but be invoked when the event happens in wxDocMDIParentFrame.
Without it, we would have needed deriving a new class just to define this
handler, which would be completely disproportionate.


 Before ending this message, let me describe the other patches I attached.
They are completely optional, but I couldn't prevent myself from making
them while looking at the code related to the MDI frames event handling.

 The 0002-Don-t-count-all-MDI-children-just-check-if-there-is-.patch one
addresses my urge to avoid performing unnecessary actions: we don't really
need the count of MDI children frame here at all, so why bother counting
all of them (even if "all" is probably virtually always just a few) when we
can stop after just the second one? Subsidiarily, why count them at all if
we don't have any active child anyhow.

 The 0003-Remove-unnecessary-DocMDIChildFrameEx-dtor.patch removes a
"WX !!" comment which is not relevant any more (and since quite some time,
too), bringing the total count of such remaining comments to "only" 45 (2%
decrease!).

 Finally, 0004-Remove-the-attempts-to-use-MDI-parent-status-bar-for.patch
is IMHO worth applying because this code is totally misleading -- and, in
fact, managed to confuse me quite thoroughly. The truth is, it doesn't do
absolutely anything and, to the best of my knowledge, never did. As the
commit message for this change explains, this event handler was never
executed and so all the efforts to provide the correct status bar to the
help string display code inside wxWidgets were in vain. As an aside, there
is a simpler and more direct way to do this, which is to override wxFrame
DoGiveHelp() virtual method to use another status bar. But we don't even
need to do this  because wxEVT_MENU_HIGHLIGHT is sent to the parent frame
anyhow and it, of course, already uses the correct status bar. So I don't
believe there is any reason to keep this code and less code is always good.

 And to really conclude this topic, I'd like to add that, while debugging
this, I did find a minor problem related to the help strings: they were not
shown at all for the items in a popup menu (e.g. the one shown when right
clicking in a census window). Unfortunately this is something that can't be
worked around at LMI level, it turned out to be a real bug in wxWidgets and
I had to fix it there. Nothing is required for this fix to work for LMI:
when you update to a later revision (I can't give the exact commit as I
haven't committed it just yet because the wxWidgets svn repository server
has some problems right now), whether you apply the above patch or not, you
will just see the help strings in the status bar for the popup menu items
as well.

 As always, please let me know if you have any questions about these
patches,
VZ

Attachment: 0001-Handle-only-the-menu-open-events-for-the-main-frame-.patch
Description: Text document

Attachment: 0002-Don-t-count-all-MDI-children-just-check-if-there-is-.patch
Description: Text document

Attachment: 0003-Remove-unnecessary-DocMDIChildFrameEx-dtor.patch
Description: Text document

Attachment: 0004-Remove-the-attempts-to-use-MDI-parent-status-bar-for.patch
Description: Text document


reply via email to

[Prev in Thread] Current Thread [Next in Thread]