[Top][All Lists]

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

Re: [lmi] UpdateUI problems in main_wx.cpp

From: Greg Chicares
Subject: Re: [lmi] UpdateUI problems in main_wx.cpp
Date: Sat, 23 Aug 2008 16:48:27 +0000
User-agent: Thunderbird (Windows/20080708)

On 2008-08-07 19:32Z, Vadim Zeitlin wrote:
>  The only remaining related problem is this part of Skeleton class event
> table definition:
> // TODO ?? There has to be a better way.
> /*
>     EVT_UPDATE_UI(XRCID("edit_cell"            
> ),Skeleton::UponUpdateInapplicable)
> ... 13 more event handlers snipped ...
>     EVT_UPDATE_UI(XRCID("column_width_fixed"   
> ),Skeleton::UponUpdateInapplicable)
> */
> Unfortunately I don't have any satisfactory solution to it. There is
> EVT_UPDATE_UI_RANGE() but nothing guarantees that the numeric values of the
> corresponding ids are going to be consecutive, strictly speaking (even if
> this is very likely in practice). And I don't think there is any way to
> define a consecutive range of ids in the XRC. I hope Vaclav would correct
> me if I'm wrong.

Writing one EVT_UPDATE_UI_RANGE entry would be more appealing than
writing fifteen distinct handlers that all map to the same function,
if it were feasible and guaranteed to work. But there's no real
problem if that's not feasible.

However, there remains the real problem that this stuff doesn't work,
which I guess is why I commented it out. Here's the desired behavior:

  XRCID("edit_cell")  enabled iff CensusView or IllustrationView focused
  XRCID("edit_class") enabled iff CensusView focused
  ...thirteen other items [0] enabled just like XRCID("edit_class")

I've tried to express that declaratively, in three source files, e.g.:

    EVT_UPDATE_UI(XRCID("edit_case"), IllustrationView::UponUpdateInapplicable)
    EVT_UPDATE_UI(XRCID("edit_case"),       CensusView::UponUpdateApplicable)
//  EVT_UPDATE_UI(XRCID("edit_case",          Skeleton::UponUpdateInapplicable)

The entry in "Skeleton" (the wxApp-derived class) is commented out
because I never managed to get it to do what I wanted. In the view
classes, the handlers are simple:
  the   Applicable handers merely call event.Enable(true), and
  the Inapplicable handers merely call event.Enable(false).

The observed behavior is as desired, iff a IllustrationView or
CensusView child is focused--but not when no child exists. I can show
that the view-class handlers are called by writing to the statusbar:

  void CensusView::UponUpdateApplicable(wxUpdateUIEvent& e)
+     status() << "Enabled in CensusView" << std::flush;

(and similarly in IllustrationView::UponUpdateInapplicable()).

The fifteen EVT_UPDATE_UI entries for the wxApp-derived class are
commented out, so I experimentally un-comment them now, supposing that
they'll do the right thing in the case where no child exists--if only
I can write Skeleton::UponUpdateInapplicable() correctly. That handler
has an empty body (except for comments) in HEAD already, so I expect
that this change will have no effect. However, it has a bad effect:
the view-class EVT_UPDATE_UI handlers aren't called at all anymore;
I'm sure of that because their statusbar messages no longer appear.

Now I try an additional experiment, which I expect to have no effect:

  void Skeleton::UponUpdateInapplicable(wxUpdateUIEvent& event)
+     event.Skip();

but it has an apparently-desirable effect: it undoes the "damage"
caused by the first part of the experiment (activating the wxApp-class
event-table entries), and the view-class statusbar messages now appear
again. I'm mystified. I consult this page again:


The sixth of six steps is
  "Finally, ProcessEvent is called on the wxApp object."
My latest layer of experimentation only changed the wxApp object's
handler, and all I did there was call Skip():


Skip() controls "whether further event handlers bound to this event
will be called after the current one returns"; but how can there be
any further handlers, since this is reached only in the sixth step,
described as "Finally"? Surely class wxApp itself has no builtin
handler for my XRCID?

Though I can't explain the behavior, I seem to be able to exercise
some control over it, so I forge ahead, rewriting the handler in
the wxApp-derived class as follows:

  void Skeleton::UponUpdateInapplicable(wxUpdateUIEvent& event)

      int child_frame_count = 0;
      wxWindowList wl = frame_->GetChildren();
      for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i)
          child_frame_count += !!dynamic_cast<wxMDIChildFrame*>(*i);
      if(0 == child_frame_count)
          status() << "Disabled in Skeleton" << std::flush;

Here's another surprise: "Disabled in Skeleton" appears on the
statusbar, but the toolbar button is not disabled. This smells like a
problem I once solved, and indeed this change:

        status() << "Disabled in Skeleton" << std::flush;
+       event.Skip(false);

seems to achieve the desired behavior. Please help me understand why.

At least two issues remain. First, it seems that counting child
frames can't be the simplest solution: is there a better way? Second,
behavior is correct as long as no view class other than those named
above is used, but incorrect with product-editor view classes. I can
solve that by brute force, by adding fifteen entries like
    EVT_UPDATE_UI(XRCID("edit_case"), AnotherViewClass::UponUpdateInapplicable)
to every other view class; but it seems wrong to require all other
classes to know anything about toolbar buttons that pertain only to
CensusView or IllustrationView. Perhaps the wxApp-derived class's
handler should determine whether the current child frame belongs to
either of those two classes, instead of counting child frames and
comparing the count to zero? That'd be better (if it works), but I
hope there's a really elegant way that I just haven't imagined.


[0] "thirteen other items"

All fifteen XRCIDs correspond to menuitems. Only thirteen of those
correspond to toolbar buttons, but that's okay, and unimportant here.

reply via email to

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