wxNotebook

Introduction

The wxNotebook (wxWidgets: wxNotebook Class Reference) control manages a set of pages. Tabs allow the user to select the page to display. The control is shown in Figure 1 below.

Figure 1: The wxNotebook Control

Simple Example

Below we show a simple example of a wxNotebook control. The example is a simple modification of the MinimalApp2 example we presented in the minimal application tutorial. The full source for this example is available from our GitHub repository: wxWidgetsTutorials/BookControls/WxNotebook1.

 File: BookControls/WxNotebook1/src/WxNotebook1Frame.cpp
#include "WxNotebook1Frame.h"
#include <wx/panel.h>
#include <wx/notebook.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>

WxNotebook1Frame::WxNotebook1Frame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title)
{
    // Create a top-level panel to hold all the contents of the frame
    wxPanel* panel = new wxPanel(this, wxID_ANY);

    // Create the wxNotebook widget
    wxNotebook* notebook = new wxNotebook(panel, wxID_ANY);

    // Add 2 pages to the wxNotebook widget
    wxTextCtrl* textCtrl1 = new wxTextCtrl(notebook, wxID_ANY, L"Tab 1 Contents");
    notebook->AddPage(textCtrl1, L"Tab 1");
    wxTextCtrl* textCtrl2 = new wxTextCtrl(notebook, wxID_ANY, L"Tab 2 Contents");
    notebook->AddPage(textCtrl2, L"Tab 2");

    // Set up the sizer for the panel
    wxBoxSizer* panelSizer = new wxBoxSizer(wxHORIZONTAL);
    panelSizer->Add(notebook, 1, wxEXPAND);
    panel->SetSizer(panelSizer);

    // Set up the sizer for the frame and resize the frame
    // according to its contents
    wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL);
    topSizer->SetMinSize(250, 100);
    topSizer->Add(panel, 1, wxEXPAND);
    SetSizerAndFit(topSizer);
}

The application is shown in Figure 2 below.

Figure 2: The WxNotebook1 Application

The rest of the source files don't contain significant changes but are shown here for completeness.

 File: BookControls/WxNotebook1/src/WxNotebook1Frame.h
#ifndef _TUTORIALS_WXWIDGETS_WXNOTEBOOK1FRAME_H_
#define _TUTORIALS_WXWIDGETS_WXNOTEBOOK1FRAME_H_

#include <wx/frame.h>

class WxNotebook1Frame : public wxFrame
{
public:
    WxNotebook1Frame(const wxString& title);
};

#endif
 File: BookControls/WxNotebook1/src/WxNotebook1App.h
#ifndef _TUTORIALS_WXWIDGETS_WXNOTEBOOK1APP_H_
#define _TUTORIALS_WXWIDGETS_WXNOTEBOOK1APP_H_

#include <wx/app.h>

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

#endif
 File: BookControls/WxNotebook1/src/WxNotebook1App.cpp
#include "WxNotebook1App.h"
#include "WxNotebook1Frame.h"

wxIMPLEMENT_APP(WxNotebook1App);

bool WxNotebook1App::OnInit()
{
    WxNotebook1Frame* frame = new WxNotebook1Frame(L"WxNotebook1");
    frame->Show(true);
    return true;
}

Page Change Events

We will now show how to make use of the events generated when a user changes the selected page. Two events are relevant:

  • The EVT_NOTEBOOK_PAGE_CHANGING event is generated when the page selection change is initiated but the selected page hasn't changed yet.
  • The EVT_NOTEBOOK_PAGE_CHANGED event is generated after the selected page has been changed.

A simple example showing handlers for these events is presented below. The events are used to update the contents of a wxTextCtrl control.The full source for this example is available from our GitHub repository: wxWidgetsTutorials/BookControls/WxNotebook2.

The following changes were made to the previous example:

  • A wxTextCtrl control has been added to the main window to display some information that changes when some events happen.
  • The OnPageChanging handler was added to handle EVT_NOTEBOOK_PAGE_CHANGING events. It keeps track of how many times it was called in the m_pageChangingCount variable. The count will be displayed in the wxTextCtrl control.
  • The OnPageChanged handler was added to handle EVT_NOTEBOOK_PAGE_CHANGED events. It updates the contents of the wxTextCtrl control.
  • Some minor changes to improve the layout: the size of the wxNotebook control is fixed in the sizer and the minimum size of the main window sizer has been increased to 350.

The changes are highlighted in the source files shown below.

 File: BookControls/WxNotebook2/src/WxNotebook2Frame.h
#ifndef _TUTORIALS_WXWIDGETS_WXNOTEBOOK2FRAME_H_
#define _TUTORIALS_WXWIDGETS_WXNOTEBOOK2FRAME_H_

#include <wx/frame.h>
#include <wx/notebook.h>
#include <wx/textctrl.h>

class WxNotebook2Frame : public wxFrame
{
public:
    WxNotebook2Frame(const wxString& title);

private:
    void OnPageChanging(wxNotebookEvent& evt);
    void OnPageChanged(wxNotebookEvent& evt);

private:
    wxTextCtrl* m_mainContents;
    unsigned int m_pageChangingCount;

    wxDECLARE_EVENT_TABLE();
};

#endif
 File: BookControls/WxNotebook2/src/WxNotebook2Frame.cpp
#include "WxNotebook2Frame.h"
#include "WindowIDs.h"
#include <wx/panel.h>
#include <wx/sizer.h>
#include <sstream>

WxNotebook2Frame::WxNotebook2Frame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title), m_pageChangingCount(0)
{
    // Create a top-level panel to hold all the contents of the frame
    wxPanel* panel = new wxPanel(this, wxID_ANY);

    // Create the wxNotebook widget and give it a specific window id that
    // will be used to identify this widget in the event table
    wxNotebook* notebook = new wxNotebook(panel, MainContentID);

    // Add 2 pages to the wxNotebook widget
    wxTextCtrl* textCtrl1 = new wxTextCtrl(notebook, wxID_ANY, L"Tab 1 Contents");
    notebook->AddPage(textCtrl1, L"Tab 1");
    wxTextCtrl* textCtrl2 = new wxTextCtrl(notebook, wxID_ANY, L"Tab 2 Contents");
    notebook->AddPage(textCtrl2, L"Tab 2");

    // Create the right-hand side panel, it's simply a textbox
    m_mainContents = new wxTextCtrl(panel, wxID_ANY, L"Main Contents Area");

    // Set up the sizer for the panel
    wxBoxSizer* panelSizer = new wxBoxSizer(wxHORIZONTAL);
    panelSizer->Add(notebook, 0, wxEXPAND);
    panelSizer->Add(m_mainContents, 1, wxEXPAND);
    panel->SetSizer(panelSizer);

    // Set up the sizer for the frame and resize the frame
    // according to its contents
    wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL);
    topSizer->SetMinSize(350, 100);
    topSizer->Add(panel, 1, wxEXPAND);
    SetSizerAndFit(topSizer);
}

// Called when the selected page in the wxNotebook is going to be
// changed. We simply keep a count that we display on the right-hand
// side to show that the function is being called.
// In practice you may not need to write a handler for this event at
// all.
void WxNotebook2Frame::OnPageChanging(wxNotebookEvent& evt)
{
    ++m_pageChangingCount;
    evt.Skip();
}

// Called when the selected page in the wxNotebook has been changed.
// In our example we update the contents of the righ-hand side textbox.
void WxNotebook2Frame::OnPageChanged(wxNotebookEvent& evt)
{
    std::wstringstream contents;    
    switch (evt.GetSelection())
    {
    case 0:
        contents << L"Tab 1 selected, page changed ";
        break;

    case 1:
        contents << L"Tab 2 selected, page changed ";
        break;
    }
    contents << m_pageChangingCount << " times";
    m_mainContents->SetValue(contents.str());
    evt.Skip();
}

// Add the 2 event handlers to the event table. As you can see we use
// the window ID to link the event handlers to the wxNotebook we created.
wxBEGIN_EVENT_TABLE(WxNotebook2Frame, wxFrame)
    EVT_NOTEBOOK_PAGE_CHANGING(MainContentID, WxNotebook2Frame::OnPageChanging)
    EVT_NOTEBOOK_PAGE_CHANGED(MainContentID, WxNotebook2Frame::OnPageChanged)
wxEND_EVENT_TABLE()

The behaviour of the WxNotebook2 application is shown in the 3 figures below.

Figure 3: The WxNotebook2 application at startup

Figure 4: The WxNotebook2 application after tab 2 has been selected

Figure 5: The WxNotebook2 application after the user has switched between tabs 6 times

The rest of the source files don't contain significant changes but are shown here for completeness.

 File: BookControls/WxNotebook2/src/WindowIDs.h
#ifndef _TUTORIALS_WXWIDGETS_WINDOWIDS_H_
#define _TUTORIALS_WXWIDGETS_WINDOWIDS_H_

#include <wx/defs.h>

const wxWindowID MainContentID = wxID_HIGHEST + 1;

#endif
 File: BookControls/WxNotebook2/src/WxNotebook2App.h
#ifndef _TUTORIALS_WXWIDGETS_WXNOTEBOOK2APP_H_
#define _TUTORIALS_WXWIDGETS_WXNOTEBOOK2APP_H_

#include <wx/app.h>

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

#endif
 File: BookControls/WxNotebook2/src/WxNotebook2App.cpp
#include "WxNotebook2App.h"
#include "WxNotebook2Frame.h"

wxIMPLEMENT_APP(WxNotebook2App);

bool WxNotebook2App::OnInit()
{
    WxNotebook2Frame* frame = new WxNotebook2Frame(L"WxNotebook2");
    frame->Show(true);
    return true;
}