lmi
[Top][All Lists]
Advanced

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

Re: [lmi] Overriding wx member functions


From: Greg Chicares
Subject: Re: [lmi] Overriding wx member functions
Date: Fri, 02 Dec 2005 02:59:31 +0000
User-agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)

On 2005-12-1 15:47 UTC, Vadim Zeitlin wrote:
> On Tue, 29 Nov 2005 19:50:12 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> No, it didn't help. I looked into it and here's what I found.
> GC> 
> GC> The 'Face' tab is selected (using the keyboard).
> GC> 
> GC> Its first control receives focus (as reported by diagnostic code I
> GC> temporarily added to the EVT_CHILD_FOCUS handler).
> GC> 
> GC> Then the EVT_UPDATE_UI handler is called. One of its effects is to
> GC> disable the focused control.
> 
>  I'm afraid that I can't really say what happens to the focus when you
> disable the control having it currently. IMHO this shouldn't be done if
> possible.

Well, lmi's MVC framework must enable and disable controls: that's one
of its principal raisons d'ĂȘtre. And sometimes it will disable the
control that has focus: that's a consequence of using the EVT_UPDATE_UI
pseudoevent only, instead of handling all the myriad change events that
controls can generate, and factoring the design into a Model, a View,
and a Controller.

The problems can be worked around using some of your advice below.

> GC> At this point, temporary diagnostic
> GC> code in the EVT_UPDATE_UI handler reports that
> GC>   0 == FindFocus()
> GC> is true.
> GC> 
> GC> In your opinion should wx prevent this condition?
> 
>  Yes, I guess it should but I think it would be better to avoid this
> situation entirely.

To avoid it entirely, I think the MVC framework needs to do something
like the following whenever it disables a control:

  if(FindFocus() == control_about_to_be_disabled)
      ResetFocusOptimally(); // This is the nonobvious part.

or do something equivalent in the EVT_UPDATE_UI handler; and the
problem becomes writing that 'nonobvious' function.

> GC> Is there an easy way to distinguish controls that would normally
> GC> accept input from things like groupboxes?
> 
>  Yes: wxWindow::AcceptsFocus() should be what you need. But I think the
> simplest would be to just call CurrentPage()->SetFocus(): wx will then
> find the first control accepting focus itself.

Unfortunately, that doesn't do what we might think, at least not in
wx-2.5.4 .

I replaced all three occurences of this:

+         CurrentPage().SetFocus();
-         SetFocus();

in this file
  
http://savannah.nongnu.org/cgi-bin/viewcvs/*checkout*/lmi/lmi/xml_notebook.cpp?rev=1.12
and rebuilt with cvs as of the time I'm writing this message, and,
as a result, navigating to the 'Face' tab with the keyboard produces
this messagebox:

  No window has focus.
  [file C:/lmi/src/lmi/xml_notebook.cpp, line 641]

so that change makes it worse. It seems to reproduce the original
problem report in item (2) here:
  http://lists.gnu.org/archive/html/lmi/2005-11/msg00036.html
except that now I'm trapping the cause and popping up a messagebox.
So this undoes what revision 1.11 accomplished [1].

However, your suggestion

>  [...] wxWindow::AcceptsFocus() should be what you need.

does work better than either of these:

  // Call wxNotebook::SetFocus().
  // Sometimes, this focuses a notebook tab.
  // I suspect that happens if the first control that would
  // accept focus is disabled.
  SetFocus();

  // Call wxNotebookPage::SetFocus().
  // Because wxNotebookPage is a typedef for wxWindow, I think
  // that really just calls SetFocus() on the current wxPanel.
  // This doesn't fix the problem: after this call, it's
  // possible for (0 == FindFocus()) to be true.
  CurrentPage().SetFocus(); // Doesn't fix the problem.

with here's an unpolished implementation that works nicely AFAICT:

  void XmlNotebook::ResetFocusOptimally()
  {
      if(0 == FindFocus() || !FindFocus()->IsEnabled())
          {
          // Focus the notebook first. At least some window will
          // therefore have focus, even if we can't find a better
          // window to give focus to.
          SetFocus();
          // Try to find a better window to focus.
          wxWindowList wl = CurrentPage().GetChildren();
          for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i)
              {
              wxWindow* w = *i;
              if(w && w->IsEnabled() && w->AcceptsFocus())
                  {
                  w->SetFocus();
                  break;
                  }
              }
          }
  }

That seems not to focus a notebook tab as long as there's any control
on the tab for which AcceptsFocus() is true. If the latest wx doesn't
do something equivalent, then I think this would be a nice library
enhancement. But maybe it was already fixed after 2.5.4 .

There's still a (different) problem, footnoted above:

[1] But revision 1.11's change is defective too: its nobody-has-focus
detection is triggered when the application is deactivated then
reactivated (as with alt-Tab in msw) while the notebook is displayed.
That occurs even with the above ResetFocusOptimally().

This problem is iatrogenic. Having suffered from the nobody-has-focus
problem, I wanted to trap it and make its existence obvious. However,
initial experiments suggest that calling ResetFocusOptimally() as the
first step in the EVT_UPDATE_UI handler fixes this problem too.




reply via email to

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