Search Contact information
University of Cambridge Home Department of Engineering
University of Cambridge >  Engineering Department >  computing help

wxWidgets

Contents

wxWidgets is a way to write Graphical User Interfaces (GUIs, with buttons, menus, etc) for Win32, Mac OS X, etc from C++, Python, Perl, and C#/.NET. It's used in our IIA Software Engineering Project. Though it's cross-platform, the resulting programs don't look the same on all machines - they follow the look-and-feel of the machine.

This document briefly introduces wxWidgets when used with C++, highlighting a few issues that sometimes puzzle newcomers.

Programming style

Whereas other graphics libraries we use at CUED (OpenGL and GLUT) aren't Object-Oriented, wxWidgets is, so you need some awareness of using C++ classes.

wxWidgets also uses Macros: they're not difficult, but you may not have seen them before. By convention they have upper-case names (e.g. IMPLEMENT_APP). They're not functions - the pre-processor expands them into "inline" C/C++ before the code reaches the compiler. Here's an example of writing and using a macro to convert Celsius to Fahrenheit

#define CTOF(x) ((x*1.8) +32)
...
float fboilingpoint=CTOF(100);

Concepts

The basic concepts are much the same as in most graphics systems.

Programs with GUIs often have quite a different organisation to non-GUI programs. wxWidgets-based programs for example don't even have have an explicit main procedure. What you do is create the widgets and set things up so that the appropriate callbacks are called. Then you call the main event-loop, giving control over to the application. From then on, the program waits for events. When they happen, the program calls the appropriate callback then waits for the next event. Exiting the loop exits from the program.

Writing a program

Here are the main steps. Full code is in the next section

Compiling an example

This compile line

 g++ -o foo foo.cc  `wx-config --unicode=no --cxxflags` `wx-config --unicode=no --libs` -lglut -lGL -lGLU
(the quote-marks go from top-left to bottom-right) will compile the following code (foo.cc) producing a program called foo (if you get a warning about a deprecated or antiquated header don't worry).
// Adapted from an example by Dr Gee (CUED)
#include <wx/wx.h>
#include <GL/glut.h>
#include <iostream>

class MyFrame: public wxFrame
{
 public:
  MyFrame(wxWindow *parent, const wxString& title, const wxPoint& pos, 
          const wxSize& size);
 private:
  void OnExit(wxCommandEvent& event) { Close(true); };   
  void OnButton1(wxCommandEvent& event) {
       std::cout << "Button 1 Pressed" << std::endl;
  }; 
  void OnButton2(wxCommandEvent& event) {
       std::cout << "Button 2 Pressed" << std::endl;
  };
  DECLARE_EVENT_TABLE()
};
    
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  EVT_MENU(wxID_EXIT, MyFrame::OnExit)
  EVT_BUTTON(1, MyFrame::OnButton1)
  EVT_BUTTON(2, MyFrame::OnButton2)
END_EVENT_TABLE()
  
MyFrame::MyFrame(wxWindow *parent, const wxString& title, const wxPoint& pos, 
         const wxSize& size):
  wxFrame(parent, wxID_ANY, title, pos, size)
{
  wxMenu *fileMenu = new wxMenu;
  // The '&' in the next line underlines the succeeding character 
  fileMenu->Append(wxID_EXIT, "&Quit");
  wxMenuBar *menuBar = new wxMenuBar;

  menuBar->Append(fileMenu, "&File");
  SetMenuBar(menuBar);

  wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
  button_sizer->Add(new wxButton(this, 1, "button 1"), 0, 
                wxALL, 10);
  button_sizer->Add(new wxButton(this, 2, "button 2"), 0, 
                wxALL, 10);
  button_sizer->Add(new wxStaticText(this, wxID_ANY, "Some Text"), 0, 
                wxTOP|wxLEFT|wxRIGHT, 10);
 SetSizer(button_sizer);
}

class MyApp: public wxApp
{
 public:
  bool OnInit() {
  glutInit(&argc, argv);
  MyFrame *frame = new MyFrame(NULL, "Testing", wxDefaultPosition,  
                       wxSize(250, 150));
  frame->Show(true);
  return(true); // enter the GUI event loop
  };
};

IMPLEMENT_APP(MyApp)
The following part of the constructor for MyFrame may need an explanation.
MyFrame::MyFrame(....):
  wxFrame(parent, wxID_ANY, title, pos, size)

When a derived object is created, it will by default first call the default constructor of the class it's derived from. In this case however, we don't want to call wxFrame's default constructor, we want to pass some arguments down. It's a constructor "with a member initialiser list"

Troubleshooting

If your program compiles but doesn't work properly

Strings

You've already met C strings (character arrays) and C++ strings (the string data type). wXwidgets has its own string type called wxString which they suggest you use throughout your program - it has better internationalisation support as well as the features that C++ strings offer. See Converting everything to and from wxString for further information. To convert from a C++ string to a wxString you can try the following

  string s="hello";
  wxString mystring(s.c_str(), wxConvUTF8);

Sources of wxWidgets information

You'll need to find some on-line information. Here are some suggestions

See Also

© Cambridge University Engineering Dept
Information provided by Tim Love (tpl) with help from Dr Gee
Last updated: June 2011