|
|
|||
![]() |
Department of Engineering |
| University of Cambridge > Engineering Department > computing help |
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.
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);
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.
Here are the main steps. Full code is in the next section
class MyApp: public wxApp
{
public:
bool OnInit(); // automatically called when the application starts
};
Then calling the macro
IMPLEMENT_APP(MyApp)will create an object of that type and call its OnInit() member function.
glutInit(&argc, argv); MyFrame *frame = new MyFrame(NULL, "Testing", wxDefaultPosition, wxSize(250, 150)); frame->Show(true); return(true); // enter the GUI event loop
class MyFrame: public wxFrame ...The wxFrame class provides a frame window - a window whose size can be changed. The MyFrame class constructor is where various widgets will be created.
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()The BEGIN_EVENT_TABLE macro declares that MyFrame, which is derived from wxFrame, owns this event table.
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"
If your program compiles but doesn't work properly
#if (wxMINOR_VERSION < 8) #define wxFD_OPEN wxOPEN #endifto your source
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);
| | computing help | Graphics | |