Opened 5 years ago

Last modified 5 years ago

#14819 confirmed defect

Clicking on a panel doesn't restore focus to correct child in wxGTK

Reported by: shaurz Owned by:
Priority: normal Milestone:
Component: wxGTK Version: stable-latest
Keywords: Cc:
Blocked By: Blocking:
Patch: no


The current implementation wxWindowGTK::SetFocus() calls gtk_widget_child_focus(widget, GTK_DIR_TAB_FORWARD). Unfortunately this causes the *next* child widget (in tab order) of the container to be focused if a child widget had already been previously focused. The fix is to focus GtkContainer::focus_child if has been set.

Fix attached.

Attachments (1)

setfocus.cpp download (1.7 KB) - added by shaurz 5 years ago.

Download all attachments as: .zip

Change History (4)

Changed 5 years ago by shaurz

comment:1 Changed 5 years ago by vadz

So do I understand correctly that calling SetFocus() on the container when the focus is on one of its children moves the focus to the next child? If so, why do we need to call gtk_widget_grab_focus() at all, couldn't we just do nothing in this case?

comment:2 Changed 5 years ago by shaurz

For example, if you have a panel with 2 controls on it. Click on one of the controls, then focus another panel, then click on the original panel. It should focus the control that was previously focused, but instead it focuses the second control that was never clicked. The focus_child member is how GTK remember which child to refocus in a container (since a container itself never gets focus unless it has no child controls).

We discovered this problem with the HyperTreeList control with checkboxes. Every time you clicked the tree control it would cycle through the checkboxes.

comment:3 Changed 5 years ago by vadz

  • Status changed from new to confirmed
  • Summary changed from Fix for wxWindowGTK::SetFocus() to Clicking on a panel doesn't restore focus to correct child in wxGTK

I don't think the problem is in this function at all, in particular modifying it as suggested doesn't fix it for me. The real problem is that when using "generic" (i.e. implemented by wx itself) focus handling, we remember last focused child in each of the panels. But when using native support for it, we don't do this at all, see src/common/containr.cpp. And so every time you set focus to a panel, it's set to its first child. Which is exactly what I see with this simple example:

  • samples/minimal/minimal.cpp

    diff --git a/samples/minimal/minimal.cpp b/samples/minimal/minimal.cpp
    index a78e462..a58a845 100644
    a b bool MyApp::OnInit() 
    172172    CreateStatusBar(2);
    173173    SetStatusText("Welcome to wxWidgets!");
    174174#endif // wxUSE_STATUSBAR
     176    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
     178    wxPanel* p1 = new wxPanel(this);
     179    wxSizer* sizer1 = new wxBoxSizer(wxVERTICAL);
     180    sizer1->Add(new wxButton(p1, wxID_OK), wxSizerFlags().Border());
     181    sizer1->Add(new wxButton(p1, wxID_CANCEL), wxSizerFlags().Border());
     182    p1->SetSizer(sizer1);
     183    sizer->Add(p1);
     185    wxPanel* p2 = new wxPanel(this);
     186    wxSizer* sizer2 = new wxBoxSizer(wxVERTICAL);
     187    sizer2->Add(new wxButton(p2, wxID_OPEN), wxSizerFlags().Border());
     188    sizer2->Add(new wxButton(p2, wxID_SAVE), wxSizerFlags().Border());
     189    p2->SetSizer(sizer2);
     190    sizer->Add(p2);
     192    SetSizerAndFit(sizer);

To be honest I don't really see how could this work at all... The only possibility I see is to not do anything at all when the panel is clicked in wxGTK but this hardly seems ideal neither.

Any other/better ideas?

Note: See TracTickets for help on using tickets.