c++wxwidgets

How to correctly bind toolbook options to a menu option?


I have a menu with two custom options : OptionA and Option B

My objective is to get two toolbook options, A1 and A2, when clicking OptionA on the menubar

This is my code (mainly taken from minimum sample in wxWidgets repo):

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

wxIMPLEMENT_APP(MyApp);

class MyFrame : public wxFrame
{
public:
    MyFrame();

private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void onOptionA(wxCommandEvent& event);

    wxPanel* panel = new wxPanel(this);
    wxToolbook* tabControl1 = new wxToolbook(panel, wxID_ANY, {10, 10}, {370, 250}, /*wxTBK_BUTTONBAR|*/wxTBK_HORZ_LAYOUT);

    wxNotebookPage* tabA1 = new wxNotebookPage(tabControl1, wxID_ANY);
    wxNotebookPage* tabA2 = new wxNotebookPage(tabControl1, wxID_ANY);
    wxDECLARE_EVENT_TABLE();
};

enum
{
    ID_Hello = 1,
    ID_OptionA = 2
};

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_OptionA, MyFrame::onOptionA)
wxEND_EVENT_TABLE()

MyFrame::MyFrame()
    : wxFrame(nullptr, wxID_ANY, "MyPrj")
{

    if (wxPlatformInfo::Get().GetOperatingSystemFamilyName() == "Windows") tabControl1->SetImageList(new wxImageList(16, 16));
    else if (wxPlatformInfo::Get().GetOperatingSystemFamilyName() == "Macintosh") tabControl1->SetImageList(new wxImageList(32, 
32));
    else tabControl1->SetImageList(new wxImageList(24, 24));

    wxMenu *menuFile = new wxMenu;
    menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
                     "Help string shown in status bar for this menu item");
    menuFile->AppendSeparator();
    menuFile->Append(wxID_EXIT);

    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);

    wxMenuBar *menuBar = new wxMenuBar;
    menuBar->Append(menuFile, "&File");
    menuBar->Append(menuHelp, "&Help");

    wxMenu *menuOptionA = new wxMenu;
    wxMenu *menuOptionB = new wxMenu;

    menuBar->Append(menuOptionA, "&A");
    menuBar->Append(menuOptionB, "&B");

    SetMenuBar( menuBar );

    CreateStatusBar();
    SetStatusText("Welcome to myPrj!");

    Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello);
    Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT);
    Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);


    Bind(wxEVT_MENU, [&](wxCommandEvent& event) {
        tabControl1->AddPage(tabA1, "A1", true, 0);
        tabControl1->AddPage(tabA2, "A2", false, 1);
    }, ID_OptionA);

}


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

void MyFrame::onOptionA(wxCommandEvent& event)
{
    tabControl1->AddPage(tabA1, "A1", true, 0);
    tabControl1->AddPage(tabA2, "A2", false, 1);
}

void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxMessageBox("This is a wxWidgets Hello World example",
                 "About Hello World", wxOK | wxICON_INFORMATION);
}

void MyFrame::OnHello(wxCommandEvent& event)
{
    wxLogMessage("Hello world from wxWidgets!");
}

With :

Bind(wxEVT_MENU, [&](wxCommandEvent& event) {
    tabControl1->AddPage(tabA1, "A1", true, 0);
    tabControl1->AddPage(tabA2, "A2", false, 1);
}, ID_OptionA);

when clicking OptionA on the menu, I do not get the two toolmenu options A1 and A2

If I remove ID_OptionA :

Bind(wxEVT_MENU, [&](wxCommandEvent& event) {
    tabControl1->AddPage(tabA1, "A1", true, 0);
    tabControl1->AddPage(tabA2, "A2", false, 1);
});

I strangely get the two toolbook options A1 and A2 when clicking File->Hello

What do I have to add and / or modify in order to make A1 and A2 appear when clicking "Option A" on the menu?


Solution

  • First, as already noted in comments, you need to use either Bind() xor event tables, but not both in the same window as this is at best confusing.

    Second, you do need to specify the ID when handling menu events. If you call Bind() without it, you're handling all menu events in your handler, which is probably not what you want (although you could do this and then examine event.GetId() inside the handler to decide what to do if you really wanted). If you call Bind() with the ID, as you show, it does work and your event handler will get called if you don't have anything else connecting to it too (and executing first).