wxwidgetswxnotebook

wxNotebook - How I can get height and/or wxSize value of a single tab?


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.


Solution

  • 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.