Search code examples
c++user-interfacewxwidgets

Enter closes wxWidgets application when wxPanel added


The wxWidgets hello world tutorial exhibits a strange behavior. As soon as I add a panel to the application using the following line to the MyFrame constructor:

wxPanel *panel = new wxPanel(this);

The [Return] and [Keypad Enter] keys cause the program to exit (Clean Close event detected).

Why is this? Without the wxPanel, the keys do nothing.

Here is the code with the added line:

// hworld.cpp
// Version using dynamic event routing

#include <wx/wx.h>

class MyApp : public wxApp
{
    virtual bool OnInit();
};

IMPLEMENT_APP(MyApp)


class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
};

enum
{
    ID_Quit=1,
    ID_About
};


bool MyApp::OnInit()
{
    MyFrame *frame = new MyFrame( _("Hello World"), wxPoint(50, 50),
                                wxSize(450, 350));

    frame->Connect( ID_Quit, wxEVT_COMMAND_MENU_SELECTED,
                    (wxObjectEventFunction) &MyFrame::OnQuit );
    frame->Connect( ID_About, wxEVT_COMMAND_MENU_SELECTED,
                    (wxObjectEventFunction) &MyFrame::OnAbout );

    frame->Show(true);
    SetTopWindow(frame);
    return true;
}

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
    : wxFrame( NULL, -1, title, pos, size )
{
    wxMenuBar *menuBar = new wxMenuBar;

    wxMenu *menuFile = new wxMenu;

    menuFile->Append( ID_About, _("&About...") );
    menuFile->AppendSeparator();
    menuFile->Append( ID_Quit, _("E&xit") );

    menuBar->Append(menuFile, _("&File") );

    // Added line causing failure.
    wxPanel *panel = new wxPanel(this);

    SetMenuBar(menuBar);

    CreateStatusBar();

    SetStatusText( _("Welcome to wxWidgets!") );
}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    wxMessageBox( _("wxWidgets Hello World example."),
                _("About Hello World"),
                wxOK|wxICON_INFORMATION, this );
}           

Solution

  • It's behaving now, but it's a big of a guess as to why. The program was never crashing. I traced it in debug and the close event was being called.

    This closes when [Enter] is pressed:

    wxPanel *panel = new wxPanel(this);
    

    As do all of these:

    wxPanel *panel = new wxPanel(this, wxID_ANY);
    wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition);
    wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    

    This however doesn't close with [Enter] is pressed:

    wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND);
    

    Nor do these close:

    wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND);
    wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxCLIP_CHILDREN);
    wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND | wxCLIP_CHILDREN);
    

    But this closes again:

        wxPanel *panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND | wxCLIP_CHILDREN | wxTAB_TRAVERSAL);
    

    Apparently if wxTAB_TRAVERSAL is involved in the style (it's the default for the constructor BTW) it will propagate your [Enter] keypress to the wxFrame and click the [X] close button.

    The only thing even close to a hint is a cryptic and seemingly irrelevant note in the documentation:

     Tab traversal is implemented through an otherwise undocumented intermediate wxControlContainer class from which any class can derive in addition to the normal wxWindow base class. Please see wx/containr.h and wx/panel.h to find out how this is achieved.
    if not all characters are being intercepted by your OnKeyDown or OnChar handler, it may be because you are using the wxTAB_TRAVERSAL style, which grabs some keypresses for use by child controls.
    

    This is my best guess. I don't know if this is intentional behavior or a bug.