January 29, 2004

wxWindows Example Overview

Filed under: ResearchAndDevelopment — Ryan Wilcox @ 11:15 am

Two days ago I began working with wxWindows, which is a tool that allows the user to code a program for one platform (i.e. Mac and port their code to various other platforms.

My first assignment was to learn the language by looking at the â??minimalâ? project that came as one of the samples with wxWindows. With this entry, I hope to give the reader a better understanding of what wxWindows is and how it works.

I should note that the â??minimalâ? example is exactly what its name states â?? very minimal. It consists of just a single .cpp file. At the beginning of the file we see what look to be some fairly standard include and if statements. These occur as follows:


#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif

#if defined (__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__)
#include "mondrian.xpm"
#endif

Letâ??s take a look at what each of these lines does. The first line seems to be a fairly standard include for the programs Iâ??ve seen so far. If your compiler supports precompilation, you can simply put:


#include â??wx/wx.hâ?

The second line checks to see whether or not you are using Borland C, and if so, the header includes are stopped.

The third line basically checks to see which â??flavorâ? of wxWindows is being used. Mondrian.xpm is where the icon for the program resides.

Since wxWindows uses languages like C and C++, it seems that much of the coding is done using classes. The next bit of code in the program defines the application class for your specific program.


class MyApp : public wxApp
{

MyApp will now be derived from the wxApp class, which seems to be a fairly standard procedure as far as application development goes. The next item we see in the code is the classâ??s public declaration:

public:
virtual bool OnInit();
};

OnInit is called when the application is initially started, and it provides or any initializing that needs to be done. If this function returns a false value, the application will terminate.

The next step in the code is to declare the main frame or window for the program. This is done by doing the following:


class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title);
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);

private:
DECLARE_EVENT_TABLE()
};

MyFrame will be a class that derives from the public wxFrame class, just as MyApp derived from wxApp. The first line under public will create a new frame and give the frame its title. The two void functions will handle the events passed to them when the user selects either â??Quitâ? or â??Aboutâ? from the application menu. Special notice was given in the code that these two functions should NOT be virtual. Finally, under private, we have a macro that MUST be used for any class that is going to process events.

Next in the code there are some highly important constants that must be set.


enum
{
Minimal_Quit = wxID_EXIT,
Minimal_About = wxID_ABOUT
};

These constants will contain integer values corresponding the menu item selected. The code makes special notice particularly for the About ID, because it is handled differently under the Mac platform. If the ID is not correct, it will not be placed properly under OS X (wxWindows will “move” the preferences, exit, and about menu items from where you put them to underneath the Applications menu, which is where they belong under OS X. For this to happen you either need to use the standard wxID_EXIT, wxID_ABOUT, wxID_PREFERENCES, OR set the static variable wxApp::s_macAboutMenuItemId, wxApp::s_macPreferencesMenuItemId and wxApp::s_macExitMenuItemId to be the command ids of the menu item.)

The next piece of the code we see defines the event table that MUST be present to handle the events of the given application. The table helps connect the events to the functions that will process them.


BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Minimal_Quit, MyFrame::OnQuit)
EVT_MENU(Minimal_About, MyFrame::OnAbout)
END_EVENT_TABLE()

First, we start a new event table, passing it the name of the frame we wish to use and the class from which it is derived. Then we do two event menu calls, passing each the appropriate ID, which we just specified, and the function that will process the event when it occurs. Lastly, we end the event table. Again, the event table is highly important, since that is the way we MUST talk to events in wxWindows.

Next we have another macro:


IMPLEMENT_APP(MyApp)

This macro allows for the creation of the application object during program execution, and it also implements the function wxGetApp() which will return the right type of object reference. In this case that means returning type MyApp instead of wxApp.

IMPLIMENT_APP also impliments the C main() function for you.

Following the macro declarations, we come to the real meat of the program, where the program execution lies. First we see the code for MyApp::OnInit. Note: this means that OnInit is a function of the class MyApp.


bool MyApp:Onit()
{
MyFrame *frame = new MyFrame(_T(â??Minimal wxWindows Appâ?));
frame->Show(true);
Return true;
}

Here we create a point to a new MyFrame object, and we give that object the title of â??Minimal wxWindows Appâ?. We then must show the frame. We then return true, which means that wxApp::OnRun will execute, and we will enter the main message loop of the application. If false had been returned here, the application would have exited immediately.

Next we come to the frame constructor:


MyFrame::MyFrame(const wxString& title):wxFrame(NULL, wxID_ANY, title)
{
SetIcon(wxICON(mondrian));

Here we are simply creating a MyFrame object with the title of â??titleâ?, which is derived from wxFrame. Then the icon for the frame is set with the call to SetIcon().

Next, the menu bar is created and populated.


#if wxUSE_MENUS

wxMenu *menuFile = new wxMenu;
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(Minimal_About, _T("&About...\tF1"), _T("Show about dialog"));
menuFile->Append(Minimal_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(menuFile, _T("&File"));
menuBar->Append(helpMenu, _T("&Help"));
SetMenuBar(menuBar);
#endif // wxUSE_MENUS

Here, a File menu is made by creating a new wxMenu object. Then, a Help menu is created in the same fashion. Then to both of these menus the appropriate information is appended. In the About menu, we pass the ID of the About event, the title for the menu, and a title that will be used for a status bar which will be created later in the code. The same procedure is followed for appending to the Quit menu item as well.

After the menu is created, we create a new wxMenuBar object. Then we append the File Menu and the Help menu to this menu bar by passing the appropriate menu object and the message to be displayed on the menu item.

By calling SetMenuBar(menuBar), we attach the menu we have just created to the frame of the application.

It is important to note that this code is only executed if wxUSE_MENUS is true.

Next, a status bar is created which resides (at least in OS X) in the bottom left corner of the main frame of the application.


#if wxUSE_STATUSBAR
CreateStatusBar(2);
SetStatusText(-T(â??Welcome to wxWindows!â?));
#end if
}

If wxUSE_STATUSBAR is true, then we create a new status bar with a default of 1 pane. Next the text of the status bar is set to â??Welcome to wxWindows!â?. This text can be changed, and it is changed throughout various parts of the program, depending on which event is occurring.

The next part of the code deals with the event handlers. These are the pieces of code that will handle things like: Quit, About, etc.


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

Here we see the code to handle the OnQuit event. It gets passed an unused event, and then it forces the frame to close, which is the desired effect of select quit from the menu. Note that, under wxWindows, when all your windows close, your program quits. This is not standard behavior for OS X, but it is for other platforms.

Next, we have the code for the OnAbout event.


void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
wxString msg;
msg.Printf(_T(â??This is the About dialog of the minimal sample.\nâ?)_T(â??Welcome to %sâ?), wxVERSION_STRING);
wxMessageBox(msg, _T("About Minimal"), wxOK | wxICON_INFORMATION, this);

Here the call is almost identical to that of OnQuit. The difference lies in the code executed in the function. We create a variable msg which has type wxString. Then we execute a printf statement with msg which contains the text of the About box. WxVERSION_STRING simply contains the current version of wxWindows on your machine. Then, a new wxMessageBox is created, and we pass it our msg text, the title for its frame/window, whether or not it should contain the default icon, and this (which is the object we have just created.

These two event handler functions are the last piece of the minimal.cpp file. All that remains is to compile and build the project and run the application.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.