Search code examples
c++wxwidgets

Interaction between wxPanel and wxFrame


I am trying to understand how wxFrame and wxPanel work together. I am having a hard time explaining the following code behavior:

I am trying to set up the GUI for my application. I have a function that creates a form for data entry:

void MyFrame::Initialize_Project_Info() {


//Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(600, 1000), wxTAB_TRAVERSAL, _T(""));

//Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));

Info_Box = new wxBoxSizer(wxHORIZONTAL);
Info_Staticbox = new wxStaticBoxSizer(wxHORIZONTAL, Info_Panel, _T("Project Information"));
Info_Grid = new wxFlexGridSizer(4, 2, 0, 0);


//Note wsSize(width,height).
Project_Name = new wxStaticText(Info_Panel, wxID_ANY, _T("Project:"));
Engineer_Name = new wxStaticText(Info_Panel, wxID_ANY, _T("Engineer:"));
CrossSection_Name = new wxStaticText(Info_Panel, wxID_ANY, _T("Cross Section ID:"));
Additional_Notes = new wxStaticText(Info_Panel, wxID_ANY, _T("Additional Notes:"));


Enter_PN = new wxTextCtrl(Info_Panel, ENTER_PN, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB, wxDefaultValidator, _T(""));
Enter_EN = new wxTextCtrl(Info_Panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB, wxDefaultValidator, _T(""));
Enter_CSN = new wxTextCtrl(Info_Panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB, wxDefaultValidator, _T(""));
Enter_AN = new wxTextCtrl(Info_Panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, 100), wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxTE_MULTILINE, wxDefaultValidator, _T(""));

Info_Grid->Add(Project_Name,
    wxSizerFlags().Align(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL)
    .Border(wxTOP | wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_PN, wxSizerFlags().Expand().Border(wxALL));
Info_Grid->Add(Engineer_Name,
    wxSizerFlags().Align(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL)
    .Border(wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_EN, wxSizerFlags().Expand().Border(wxBOTTOM | wxLEFT | wxRIGHT));
Info_Grid->Add(CrossSection_Name,
    wxSizerFlags().Align(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL)
    .Border(wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_CSN,
    wxSizerFlags().Expand().Border(wxBOTTOM | wxLEFT | wxRIGHT));
Info_Grid->Add(Additional_Notes,
    wxSizerFlags().Align(wxALIGN_LEFT).Border(wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_AN, wxSizerFlags().Expand().Border(wxBOTTOM | wxLEFT | wxRIGHT));

Info_Staticbox->Add(Info_Grid);
Info_Box->Add(Info_Staticbox, wxSizerFlags().Border(wxALL));
Info_Panel->SetSizer(Info_Box);

}

This code works if I append all the objects to a wxPanel when only defined in the scope of the function. If I define the wxPanel in the scope of the constructor of the wxFrame derived class, it does not work.

For example, doing this does not generate the form as intended:

MyFrame::MyFrame() : wxFrame(NULL,wxID_ANY,"Cross Sectional Beam Properties",wxDefaultPosition,wxSize(1200,600),wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)) {


Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));


Initialize_Project_Info();

}

So, my question is how does wxPanel interface with wxFrame. Why would one moving one line of code (i.e. wxPanel initialization) change the outcome?


Solution

  • From the wx docs:

    A frame is a window whose size and position can (usually) be changed by the user.
    It usually has thick borders and a title bar, and can optionally contain a menu bar, toolbar and status bar.

    A panel is a window on which controls are placed.
    It is usually placed within a frame. Its main feature over its parent class wxWindow is code for handling child windows and TAB traversal.

    wxWindow is a generic class used by any type of window. wxDialog is mainly used as a form where the user enters data.

    Usually an application shows a frame as the main window of the app.

    ==> While you can place controls directly in a wxFrame, because of 'TAB traversal' and a OS's typical background features you better use a wxPanel.

    This panel is a child of the main wxFrame and you can buid it at wxFrame's ctor. Because in wxWidgets if a wxFrame has an unique child then this child is expanded to fit the whole client size of the wxFrame, then you don't use wxsizers for this panel-to-frame fitting.

    When you create the controls (e.g. at wxPanel ctor) you set this wxPanel as the parent of the controls. And use sizers to layout them into the panel.

    So each control has your panel as parent; an your panel has the frame as parent. Don't forget that 'this' pointers may be used as parents, or pass the parent as a parameter in the function that creates the windows (panel, controls).

    Finally, the pointers to any wxWindow-derived class are created with "new", but you don't need to delete them, wxWigets internals takes care of their deletion.