Home / Software / wxMenuToolBar


wxToolBar with menu buttons: wxMenuToolBar

wxMenuToolBar is a GUI component intended to be used inside the wxWidgets GUI programming environment.

wxMenuToolBar allows you to create easy pop-up menus inside of your tool-bar. In addition, it provides a simple pop-up menu button which you can use anywhere (like in a panel, dialog box, etc.). It has been tested on both Microsoft-Windows (MSW) and Mac OS/X (MAC) and it works, and looks great.

Download the Components

MS-Windows Download: MTBSample.ZIP

Macintosh Download: MTBSample.dmg.gz

What's provided in the download:

Pictures

The sample program running on MS-Windows

The sample program running on Mac OS/X

Using wxMenuToolBar

wxMenuToolBar provides additional routines for having pop-up menus displayed in response to toolbar clicks. It is derived from wxToolBar and can be used where you might used wxToolBar, such as in your wxFrame constructor.

wxMenuToolBar contains the following methods:

wxMenuToolBar(wxFrame* parent, 
          wxWindowID id, 
          const wxPoint& pos = wxDefaultPosition, 
          const wxSize& size = wxDefaultSize, 
          long style = wxTB_HORIZONTAL | wxNO_BORDER, 
          const wxString& name = wxPanelNameStr);
wxMenuToolBar constructor. Constructs the entire tool-bar.
void AddMenuButtonTool(int toolId, 
         const wxString& label, 
         const wxBitmap& bitmap1, 
         const wxString& shortHelpString = "");
Adds a toolbar button which pops-up a menu. You choose the graphics for the toolbar button. On Windows, the toolbar button behaves exactly like any other toolbar button (i.e. when you mouse over it, tool tips, etc.). On Macintosh, unfortunately, Menu Button Tools do not provide tool-tips.
wxMenuButton *AddMenuPulldownTool(int toolId, 
                         const wxString& label, 
                         const wxString& shortHelpString = "");
Adds a special pulldown button which pops-up a menu. The button displays as a small black triangle on the toolbar. This button is typically used with some other button to it's left (like the forward/backward buttons in Firefox).

Using wxMenuButton

wxMenuButton is a simple button which displays a small black triangle. When clicked, the button will pop up a menu. wxMenuButton is derived from wxBitmapButton and can be used in dialog boxes, panels, etc.

In addition, wxMenuButton contains the following constructor routines:

    wxMenuButton(wxToolBar *toolBar, int ID);
    wxMenuButton(wxWindow *window, int ID);
    void Create(wxToolBar *toolBar, int ID);
    void Create(wxWindow *window, int ID);
wxMenuButton constructors. It positions the menu slightly differently depending on whether it is a child of a toolbar, or some other menu. Use the Create() routines for two phase button creation.

Handling Events

Both wxMenuToolBar and wxMenuButton provide a special event, wxEVT_FILL_MENU, which is transmitted whenever the user clicks on a button which is about to pop up a menu. You will need to trap this event and fill the menu provided with entries so that the user has something to select.

Specifically, include an EVT_COMMAND() in your event table, like this:

EVT_COMMAND(MY_BUTTON_ID, wxEVT_FILL_MENU, MyClass::MyFillRoutine)

Your resulting MyClass::MyFillRoutine() should look something like this:

void MyClass::MyFillRoutine(wxCommandEvent& event) {
   wxMenu *menu = (wxMenu *)event.GetClientData();
   if(menu->GetMenuItemCount() <= 0) {
     menu->Append(MY_ID1, wxT("My Menu Item 1"));
     menu->AppendSeparator();
     menu->Append(MY_ID2, wxT("My Menu Item 2"));
     // etc.
   }
}

The following is a more comprehensive example:

// *** Declaring the events
//
BEGIN_EVENT_TABLE(MyFrame, wxFrame)

  // wxEVT_FILL_MENU will be transmitted whenever the menu is going to be displayed.
  // This gives you the opportunity to fill the menu with entries, or to change the entries.
  EVT_COMMAND  (mtbID_NEW, wxEVT_FILL_MENU, MyFrame::FillNewMenu)
  
  // Once the user choose a menu item, it will fire an EVT_MENU event with the
  // id if the menu item you provided when you filled up the menu
  EVT_MENU     (mtbID_NEW_ITEM, MyFrame::ProcessNewItem)
END_EVENT_TABLE()

// Example routine for filling up the menu
void MyFrame::FillNewMenu(wxCommandEvent& event)
{
  // The menu pointer is transmitted as part of the event's ClientData
  wxMenu *menu = (wxMenu *)event.GetClientData();

  if(menu->GetMenuItemCount() <= 0) {
    menu->Append(mtbID_NEW_ITEM, wxT("New Item 1"));
    menu->AppendSeparator();
    menu->Append(mtbID_DUMMY, wxT("New Item 2"));
    menu->Append(mtbID_DUMMY, wxT("New Item 3"));
    menu->Append(mtbID_DUMMY, wxT("New Item 4"));
  }
}

// Processing selected menu items occurs just like handling any other menu
void MyFrame::ProcessNewItem(wxCommandEvent& event)
{
  wxMessageBox(wxT("Process New Item 1"), _T("Process New Item 1"), wxOK | wxICON_INFORMATION, this);
}

Get better pull-down menus in Microsoft Windows (MSW) implementations

There is an... ah... weakness with the MSW implementation of pop-up menus. Specifically, if you have the left mouse button down when the pop-up menu is displayed, you can't simply move the pointer to the item you want and then release it to select the menu item. Instead you are forced to release the mouse button, and then click a second time on the item you want.

Fortunately, with a minor change in the wxWidgets source code, you can fix this. You will need to make the change and then recompile the wxWidgets libraries.

The change needs to be made to src\msw\window.cpp, as follows:

bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
{
.
.
.

#if defined(__WXWINCE__)
UINT flags = 0;
#else
UINT flags = TPM_RIGHTBUTTON;
flags = TPM_LEFTBUTTON; // <<< ADD THIS LINE
#endif
::TrackPopupMenu(hMenu, flags , point.x, point.y, 0, hWnd, NULL); 

And that's it. Simple, no? Trust me, you'll be more than happy with the change.


Click here to contact Paul (please do).