Opened 6 years ago

#16769 new defect

wxPanel created with disabled parent can't be focused

Reported by: trivia21 Owned by:
Priority: normal Milestone:
Component: wxGTK Version: 3.0.2
Keywords: wxPanel focus enabled disabled setfocus enable Cc:
Blocked By: Blocking:
Patch: no

Description

If a wxPanel (or a non-interactive control) is created while its parent is disabled, it won't receive focus, even after the parent is enabled, SetFocus is called on the control, or the user clicks on it.
This is quite bad, for example, if you want to monitor all key down events in wxApp::FilterEvent while the frame has focus: there won't be any.
The problem doesn't exist on wxMSW. Here is the test program I've used. If DISABLE_BEFORE_PANEL is 1, the Panel doesn't receive focus, thus no key events in FilterEvent.

#include <wx/wx.h>

#define DISABLE_BEFORE_PANEL 1
#define DISABLE_AFTER_PANEL 0
#define ENABLE_AFTER_PANEL 0
#define DELAYED_SETFOCUS_PANEL 1

class cApp: public wxApp
{
public:
    virtual bool OnInit();
private:
    class cFrame * frame;
    wxTimer focustimer;

    void OnFocusTimer(wxTimerEvent &event);
};

class cFrame: public wxFrame
{
public:
    cFrame(wxWindow * parent = NULL);
    void SetFocusPanel() { panel->SetFocus(); }
private:
    wxPanel * panel;

    void OnPanelSetFocus(wxFocusEvent &event);
    void OnPanelKillFocus(wxFocusEvent &event);
};

wxIMPLEMENT_APP(cApp);

// cApp

bool cApp::OnInit()
{
    frame = new cFrame;
    frame->Show(true);
    focustimer.Bind(wxEVT_TIMER, &cApp::OnFocusTimer, this);
    focustimer.Start(1500, wxTIMER_ONE_SHOT);
    return true;
}

void cApp::OnFocusTimer(wxTimerEvent &event)
{
    frame->Enable(true); // <<-- Frame is reenabled after a delay
#ifdef DELAYED_SETFOCUS_PANEL
    frame->SetFocusPanel();
#endif
}

// cFrame

cFrame::cFrame(wxWindow * parent):
    wxFrame(parent, wxID_ANY, L"No focus events.")
{
#if DISABLE_BEFORE_PANEL
    Enable(false);
#endif
    // Panel is created here. As the single child of frame,
    // it will occupy the whole client space
    panel = new wxPanel(this);
#if DISABLE_AFTER_PANEL
    Enable(false);
#endif
#if ENABLE_AFTER_PANEL
    Enable(true);
#endif
    panel->Bind(wxEVT_SET_FOCUS, &cFrame::OnPanelSetFocus, this);
    panel->Bind(wxEVT_KILL_FOCUS, &cFrame::OnPanelKillFocus, this);
}


void cFrame::OnPanelSetFocus(wxFocusEvent &event)
{
    SetLabel(L"Panel gained focus!!");
    event.Skip();
}

void cFrame::OnPanelKillFocus(wxFocusEvent &event)
{
    SetLabel(L"Panel lost focus.");
    event.Skip();
}

Change History (0)

Note: See TracTickets for help on using tickets.