I'm writing some wxWidgets samples for educational purposes. My problem is simple: I'm using wxNotebook, and I need some trick to get current size of a single tab, especially height. In simple terms, if I place a wxNotebook inside a wxFrame which have, for example, his wxMenubar - which, obviously, take up place in height -, I would get tab height value only, NOT wxFrame height value which also includes size of wxMenubar. I need this information to properly center new components.
See the sample code below for an example.
#include "wx/wx.h"
#include "wx/gbsizer.h"
class MyFrame : public wxFrame
{
public:
MyFrame() : wxFrame(NULL, wxID_ANY, wxT("Application"), wxDefaultPosition, wxSize(500, 300))
{
wxNotebook *tabs = new wxNotebook(this, wxID_ANY, wxPoint(-1,-1), wxSize(-1,-1), wxNB_TOP);
wxPanel *extPanel = new wxPanel(tabs, wxID_ANY); // external panel will be directly added to wxNotebook
wxPanel *innerPanel = new wxPanel(extPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); /* for now, innerPanel has default size */
innerPanel->SetBackgroundColour(wxColor(0, 0, 255)); // I change background color for debug only
innerPanel->SetMinSize(wxSize(200, 200)); // I use SetMinSize() method to communicate to the sizer _required_ size for the panel
wxGridBagSizer *gbs = new wxGridBagSizer(3, 3); // I use a wxGridBagSizer to position one panel inside external
/* **** THE FOLLOWING IS THE CRITICAL LINE **** */
wxSize mainSize = this->GetSize(); /* for now, I get the _wxFRAME_ wxSize; I would get wxNOTEBOOK size instead */
wxSize innPSize = innerPanel->GetMinSize(); // I get current (Min)Size of innerPanel
wxSize emptyCellSize((mainSize.GetWidth() - innPSize.GetWidth()) / 2, (mainSize.GetHeight() - innPSize.GetHeight()) / 2);
gbs->SetEmptyCellSize(emptyCellSize); // I Use SetEmptyCellSize() method to center the inner panel
gbs->Add(innerPanel, wxGBPosition(1, 1)); // 1, 1: central cell
extPanel->SetSizer(gbs);
tabs->AddPage(extPanel, wxT("Positioning test"));
Show(true);
}
};
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
MyFrame *frame = new MyFrame();
}
};
IMPLEMENT_APP(MyApp);
As you can see, layout is imperfect. p.s. If you know another, more efficient way to center a component using wxGridBagSizer, let me know.
Centering cells of a gridbag layouts can be done by labeling the columns or rows of the grid as "growable." When a grid cell is labeled as growable, all of the cells will grow to take up all of the space given to it by the parent window (also the cells are automatically resized when the parent window is resized). For example, if you had 3 columns and wanted the middle column to be centered you can do this:
wxGridBagSizer *gbs = new wxGridBagSizer(3, 3);
gbs->AddGrowableCol(0, 1);
gbs->AddGrowableCol(1, 2);
gbs->AddGrowableCol(2, 1);
gbs->AddGrowableRow(0, 1);
gbs->Add(new wxPanel, wxGBPosition(0, 0), wxDefaultSpan, 0);
gbs->Add(innerPanel, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND | wxCENTER);
gbs->Add(new wxPanel, wxGBPosition(0, 2), wxDefaultSpan, 0);
Here, 3 columns are created; for each column the AddGrowableCol() method has to be called to make the columns expand; the proportion variable tells the size how big each column should be in relation to all others. In this case, the middle column will be twice as big as the others. The AddGrowableRow method makes sure that the columns will take up the entire height of the parent panel.