wxWidgets (4) - wxPanel And Controls (Visual C++)

wxWidgets - (4) wxPanel And Controls (Visual C++)
This tutorial continues on from the previous wxWidgets - (3) Creating A Menu Bar (Visual C++).

And here do we create some controls on its main frame and a pop menu for the application as well as starting to be accustomed to working with sizers and an advanced page control component of wxWidgets.

  1. Open the previously created wxWidgets project.

  2. Specify "#include <wx/sizer.h>", "#include <wx/aui/auibook.h>" and "#include <wx/panel.h>" in its main header file.

  3. Now let us change the size of the main frame so that it could accommodate the controls to be created afterwards :
        ....
        MainFrame(wxWindow *parent, wxWindowID id = wxID_ANY
            , const wxString &caption = wxEmptyString
            , const wxPoint &pos = wxDefaultPosition
            , const wxSize &size = wxSize(800, 600)); // Modify the size.
        void OnFrameClose(wxCloseEvent &event);
        ....
  4. Declare the following enumeration for the application's sections in its header file :
    //-------------------- (4) -------------------:
    enum enSections
    {
        secGeneral, secDirs, Projects, cisections
    };
    //----------------------------------------------------------------------------
    

  5. Declare the following variables for our controls in the private section of its header file :
        //-------------------------------(4):
        wxSizer *m_szrhFrame; // the main sizer for the frame.
    
        wxAuiNotebook m_nbkSections; // left section page control.
        wxPanel m_pnlSections[cisections]; // each page for the left section control.
        wxSizer *m_szrvSections[cisections]; // sizers for each panel.
        wxString m_SSections[cisections]; // section page captions.
    
        wxStaticText m_lblSections[cisections]; // each label for each section.
        wxSizer *m_szrhSectionLabels[cisections]; // sizer for each section label.
    
        wxPanel m_pnlMain; // main panel for all main controls of the application.
        wxSizer *m_szrvMain; // sizer for the main panel.
    
        wxSizer *m_szrhMainLabel; // sizer for the horizontal label.
        wxStaticText m_lblMainPanel; // capton for the main panel.
        //-------------------------------(4).

  6. Declare the following method for our control creation in the header file :
        void AllocFreeMainControls(bool bAlloc);
    

  7. Write down code for the controls creation in the main source file :
    //----------------------------------------------------------------------------
    void MainFrame::AllocFreeMainControls(bool bAlloc)
    {
        if (bAlloc)
        {
            m_szrhFrame = new wxBoxSizer(wxHORIZONTAL);
            this->SetSizer(m_szrhFrame);
    
            wxSize sz(wxDefaultSize);
            sz.x = 0x0100;
            m_nbkSections.Create(this, wxID_ANY, wxDefaultPosition, sz);
            wchar_t ws[0x20] = L"Page : ";
            wchar_t *pws = &ws[wcslen(ws)];
            const wxColor *clrs[] = { wxWHITE, wxYELLOW, wxGREEN };
    
            for (int i = 0x00; i < cisections; i++)
            {
                m_pnlSections[i].Create(this);
                m_pnlSections[i].SetBackgroundColour(*clrs[i]);
                m_szrvSections[i] = new wxBoxSizer(wxVERTICAL);
                m_pnlSections[i].SetSizer(m_szrvSections[i]);
    
                m_szrhSectionLabels[i] = new wxBoxSizer(wxHORIZONTAL);
                m_szrhSectionLabels[i]->AddStretchSpacer();
                _itow(i + 0x01, pws, 0x0a);
                m_lblSections[i].Create(&m_pnlSections[i], wxID_ANY, ws);
                m_szrhSectionLabels[i]->Add(&m_lblSections[i]
                    , 0x00, wxEXPAND | wxFIXED_MINSIZE | wxALL, 0x02);
                m_szrhSectionLabels[i]->AddStretchSpacer();
    
                m_szrvSections[i]->AddStretchSpacer();
                m_szrvSections[i]->Add(m_szrhSectionLabels[i], 0x00, wxEXPAND);
                m_szrvSections[i]->AddStretchSpacer();
    
                m_nbkSections.AddPage(&m_pnlSections[i], m_SSections[i], false);
                m_nbkSections.Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED
                    , &MainFrame::Onm_nbkSectionsChanged, this);
            }
            m_szrhFrame->Add(&m_nbkSections, 0x00
                , wxEXPAND | wxFIXED_MINSIZE | wxALL, 0x02);
    
            m_pnlMain.Create(this);
            m_szrvMain = new wxBoxSizer(wxVERTICAL);
            m_pnlMain.SetSizer(m_szrvMain);
    
            m_szrhMainLabel = new wxBoxSizer(wxHORIZONTAL);
            m_lblMainPanel.Create(&m_pnlMain, wxID_ANY, L"Main Panel");
            m_szrhMainLabel->AddStretchSpacer();
            m_szrhMainLabel->Add(&m_lblMainPanel, 0x00
                , wxEXPAND | wxFIXED_MINSIZE | wxALL, 0x02);
            m_szrhMainLabel->AddStretchSpacer();
    
            m_szrvMain->AddStretchSpacer();
            m_szrvMain->Add(m_szrhMainLabel, 0x00, wxEXPAND | wxALL, 0x02);
            m_szrvMain->AddStretchSpacer();
            m_szrhFrame->Add(&m_pnlMain, 0x01, wxGROW | wxALL, 0x02);
        }
        else
        {
            m_szrhFrame->Detach(&m_pnlMain);
            for (int i = cisections - 0x01; i > -0x01; i--)
            {
                m_szrvSections[i]->Detach(m_szrhSectionLabels[i]);
                delete m_szrhSectionLabels[i]; m_szrhSectionLabels[i] = NULL;
    
                m_nbkSections.RemovePage(i);
                m_pnlSections[i].SetSizer(NULL); // Its sizer is destroyed automatically.
                m_szrvSections[i] = NULL;
            }
            m_szrhMainLabel->Detach(&m_lblMainPanel);
            m_szrvMain->Detach(m_szrhMainLabel);
    
            delete m_szrhMainLabel; m_szrhMainLabel = NULL;
            m_pnlMain.SetSizer(NULL); m_szrvMain = NULL;
    
            m_szrhFrame->Detach(&m_pnlMain);
            m_szrhFrame->Detach(&m_nbkSections);
    
            this->SetSizer(NULL);
            m_szrhFrame = NULL;
        }
    }
    //----------------------------------------------------------------------------
    
    

  8. Write down code for each section change event handler :
    //----------------------------------------------------------------------------
    void MainFrame::Onm_nbkSectionsChanged(wxAuiNotebookEvent &evt)
    {
        int isel = m_nbkSections.GetSelection();
        ProcSectionChange((wxPanel *)m_nbkSections.GetPage(isel), (enSections)isel);
    }
    //----------------------------------------------------------------------------
    void MainFrame::ProcSectionChange(wxPanel *pnl, enSections sec)
    {
        m_lblMainPanel.SetLabel(m_lblSections[sec].GetLabel()
            + L" : " + m_nbkSections.GetPageText(sec));
    }
    //----------------------------------------------------------------------------
    

  9. And add the following statement in the constructor of the main frame for our main controls creation :
    
        ...
        m_SSections[secDirs]     = L"Directories";
        m_SSections[secProjects] = L"Projects";
    
        AllocFreeMainControls(true);
        AllocFreeMenuBar(true);
        ...
    

  10. Add the following statement in the frame close event handler for the controls removal :
        ...
        if (m_bmpStatus)
            delete m_bmpStatus;
        AllocFreeMenuBar(false);
        AllocFreeMainControls(false);
        ...
    

  11. Run the project and we could see the following more-or-less decent application :

    But!
    Its icon seems to be missing from the left-most side of its title bar!
    Now it's time to give it some meaningful icons:

  12. If an RC file already exists inside [Resource Files] open it via [View Code] context menu
    or right-click on the [Resource Files] category inside Visual Studio's [Solution Explorer].
    Choose [Add...] --> [Resource...].

    There will be a lot of statements in it, already. Then delete all of them to write only the following single statement line for our application icon :

    aaaICON        ICON    "wx_Ico_bettered.ico"
    

  13. Add the following statement in the top of its main constructor for its icon assignment :
    //----------------------------------------------------------------------------
    MainFrame::MainFrame(wxWindow *parent, wxWindowID id
        , const wxString &caption, const wxPoint &pos, const wxSize &size)
        : wxFrame(parent, id, caption, pos, size)
    {
        SetIcon(wxIcon(_("aaaICON")));
    
        m_bmpStatus = NULL;
        ...
    

    Then prepare the named icon ("wx_Ico_bettered.ico") in the project directory.
    And rebuild the project.

  14. Run the project and we could see the icon appear on its title bar :

  15. Now it is time for its main popup menu creation. The popup menu will be brought up whenever a mouse right-click event occurs inside the main panel :

  16. Declare a wxMenu variable for the popup menu in the private: section of the header file :
        wxMenu *m_mnpMain;
    
  17. Add the following case statement line to the previously created GetItemKind method in the private: section of the header file :
    
            ...
            case msLangJpn:
                return wxITEM_RADIO;
    
            case 0x00: //<--
            case mfSepOpen:
            case mfSepExit:
            ...
    
    

  18. Add the following statement to its constructor :
    
        ...
        m_mnpMain = NULL; // <-- Required.
        ...
    
    

  19. As it is popped up from the Main Panel, AllocFreeMainControls method needs to be changed like so for the panel to create it on the spot just before its invocation :
    
        ...
            m_pnlMain.Create(this);
            m_szrvMain = new wxBoxSizer(wxVERTICAL);
            m_pnlMain.SetSizer(m_szrvMain);
            m_pnlMain.Bind(wxEVT_RIGHT_DOWN, &MainFrame::OnMainPanelMouseRDown, this); // <--
        ...
    
    

  20. Now let's create a method for the actual popup menu creation :
    //----------------------------------------------------------------------------
    void MainFrame::AllocFreePopupMenu(bool bAlloc)
    {
        wxMenuItem *pmi;
        //--------------------------------------------------------------------
        const int ciids[] = { mfOpen, 0x00, meUndo, meRedo, 0x00, mhAbout };
        const int ciitems = sizeof(ciids) / sizeof(*ciids);
        //--------------------------------------------------------------------
        if (bAlloc)
        {
            if (m_mnpMain)
                return;
    
            wxString *pSs[] = { &m_SMenuFiles[mfOpen - IDM_FILE_START]
                , NULL, &m_SMenuEdits[meUndo - IDM_EDIT_START]
                , &m_SMenuEdits[meRedo - IDM_EDIT_START], NULL
                , &m_SMenuHelps[mhAbout - IDM_HELP_START] };
    
            wxMenuItem *pmiMain;
            wxItemKind ikKind;
            m_mnpMain = new wxMenu;
            for (int i = 0x00; i < ciitems; i++)
            {
                ikKind = GetItemKind(ciids[i]);
                pmi = new wxMenuItem(m_mnpMain, ciids[i]
                    , pSs[i]?(*pSs[i]):wxEmptyString, wxEmptyString, ikKind);
    
                pmiMain = m_menubar.FindItem(ciids[i]);
                if (pmiMain)
                {
                    pmi->SetBitmap(pmiMain->GetBitmap(true), true);
                }
    
                m_mnpMain->Append(pmi);
                this->Bind(wxEVT_MENU, &MainFrame::OnMenuClicks, this, ciids[i]);
            }
            m_pnlMain.Bind(wxEVT_CONTEXT_MENU, &MainFrame::OnMainContextMenu, this);
        }
        else if (m_mnpMain)
        {
            for (int i = ciitems - 0x01; i > -0x01; i--)
            {
                pmi = m_mnpMain->Remove(ciids[i]);
                delete pmi;
            }
            delete m_mnpMain;
            m_mnpMain = NULL;
        }
    }
    //----------------------------------------------------------------------------
    
    

  21. Write down the popup menu creation method inside the main panel's right mouse button down event handler :
    //----------------------------------------------------------------------------
    void MainFrame::OnMainPanelMouseRDown(wxMouseEvent &evt)
    {
        if (NULL == m_mnpMain)
            AllocFreePopupMenu(true);
    }
    //------------------------------------------------------------------------
    
    

  22. Let the main panel invoke the popup menu :
    //----------------------------------------------------------------------------
    void MainFrame::OnMainContextMenu(wxContextMenuEvent &evt)
    {
        if (m_mnpMain)
            ((wxWindow *)evt.GetEventObject())->PopupMenu(m_mnpMain);
    }
    //----------------------------------------------------------------------------
    
    

  23. Finally add the popup menu destruction statement inside the frame's destructor :
    
        ....
        AllocFreeMenuBar(false);
        AllocFreeMainControls(false);
        AllocFreePopupMenu(false);
        ....
    
    

  24. Let the application be known to other applications by giving it a title in case any other application or process needs it.
    Then let's add the following statement in the constructor :
    SetTitle(L"wxWidgets Sample Application v0.1");
    

  25. Run the project and we could bring up its main popup menu by right-clicking on the main panel as shown below :

    Job Done !

Download Source code for the project (Visual C++ 2013) : src_Test_Toolbar(+sb+mnb+mnp).7z (868 KB)

No comments:

Post a Comment