Beech:First steps

From WxWiki
Jump to: navigation, search

Introduction

We now look at another and much more friendly way of building windows programs using a set of class libraries called wxWidgets. Strictly speaking wxWidgets is much more than libraries, it is an application framework, which means it provides an architecture for using the classes in developing complete applications. The benefits of using wxWidgets don't stop there, it is also a cross-platform library. In the words of the wxWidgets authors:

What is wxWidgets?

  • wxWidgets gives you a single, easy-to-use API for writing GUI applications on multiple platforms. Link with the appropriate library for your platform (Windows/Unix/Mac) and compiler (almost any popular C++ compiler), and your application will adopt the look and feel appropriate to that platform. On top of great GUI functionality, wxWidgets gives you: online help, network programming, streams, clipboard and drag and drop, multithreading, image loading and saving in a variety of popular formats, database support, HTML viewing and printing, and much much more.

wxWidgets is a very high-quality piece of work, indeed, some people might use the term "commercial quality" in describing wxWidgets meaning that it is good enough to pay for. That is certainly true but if there is one criticism that has been made of wxWidgets, it is that, for a beginner, it can be difficult to come to grips with: the initial learning process is a little complex. The optimistic reply to that criticism is that once the programmer has a grasp of the wxWidgets architecture, ie it's classes, functions and techniques, writing useful applications is a very rewarding and relatively straightforward process. It can be financially rewarding too, wxWidgets is such a rich framework that almost any application domain can be tackled.

You have probably already guessed, whilst reading this, that I am a very keen supporter of wxWidgets. That's true and I'd like to communicate my enthusiasm for wxWidgets to you through these web pages.

My plan is to explain the architecture of wxWidgets and introduce the classes in wxWidgets through a series of example programs starting with the very basics. By the time you have finished you should have a good grasp wxWidgets.

Before starting, here are some notes of caution:

  • I don't consider myself to be a particularly good programmer and neither am I particularly well-versed in wxWidgets but I do have a way with words and I am confident that I can explain complex topics clearly.
  • You will need to understand C and C++ but not necessarily in great detail. Your abilities in C and C++ will be greatly extended as you learn wxWidgets. If you have worked through most of the C++ material on this web site, and understood it, I think you will have no problems.
  • You will need to understand object-oriented programming and classes. Again most of the material on this web site will help you.
  • The early work is done on a Windows platform, Win95, Win98 and Win2K have all been used. The MingW package along with wxWidgets provides the development environment.

These pages can be a great help to you if you are a beginner in programming in C++ but you want to get quickly into stride developing real-world GUI programs using wxWidgets. Come along for the ride!

The wxWidgets Architecture and Your First Program

wxWidgets basic architecture

This is the starting point and initially I have kept things quite simple. The first acquaintance with the wxWidgets framework is kept to the simplest view. As we develop further we look in more detail at the framework.

A wxWidgets GUI program consists of:

  • An application object - an instance of the wxApp class
  • A frame object - an instance of the wxFrame class. A frame can have things like a menubar, a statusbar, an icon etc.
  • The frame can be a container for many other objects like text controls, buttons, splitters and so on.

In the most simple of programs we might have just an empty frame and this is the first basic example we look at. It's reasonable to wonder what earthly use that is. It is instructive if nothing else and that's why we look at it first. You will see that it shows all the usual behaviours of a windowed application. It has a system menu, it can be moved around, it can be resized and it can be dismissed.

wxWidgets most basic application - the empty frame

I know it doesn't look much but it's ours! It also shows us that the program takes on the appearance of the native GUI. In this case it is Windows 98 but remember that wxWidgets is a cross-platform framework and could be used to develop applications for other platforms like Linux, OS2, Mac etc.

The source code for the first example is shown below.

#ifndef BASIC_H
#define BASIC_H
 
class BasicApplication : public wxApp
{
public:
	virtual bool OnInit();
};
 
class BasicFrame : public wxFrame
{
public:
	BasicFrame( const wxChar *title, int xpos, int ypos, int width, int height );
	~BasicFrame();
};
 
#endif

This is the header file. In this basic application we declare two classes:

  • BasicApplication which inherits from wxApp and
  • BasicFrame which inherits from wxFrame. We declare a constructor and destructor for BasicFrame but the only thing we do for BasicApplication is to override the OnInit() method. Note that since we are overriding we declare the method to be virtual.
#include <wx/wx.h>
#include "basic.h"
 
IMPLEMENT_APP(BasicApplication)
 
bool BasicApplication::OnInit()
{
	BasicFrame *frame = new BasicFrame(_T("Basic"), 50, 50, 450, 300);
 
	frame->Show(TRUE);
	SetTopWindow(frame);
	return TRUE;
}
 
BasicFrame::BasicFrame( const wxChar *title, int xpos, int ypos, int width, int height)
: wxFrame( (wxFrame*) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height) )
{
}
 
BasicFrame::~BasicFrame()
{
}

This is the implementation, the definition of the classes declared in basic.h.The first thing to notice is the macro IMPLEMENT_APP(BasicApplication) which, from our point of view, constructs the BasicApplication object and provides the main entry point for our application. The OnInit() method creates an instance of BasicFrame with some default x and y, width and height values and a title. It then calls the Show() method to show the frame. If you look at the wxFrame class you won't find a Show() method, wxFrame inherits from wxWindow and Show() is a wxWindow member function. As a beginner you might need to keep this is mind - since many of the classes are derived from other classes don't overlook the methods that are available in parent classes. OnInit() also calls SetTopWindow() which is a member of wxApp. The constructor and destructor don't add any new behaviors to our BasicFrame class.

#include "wx/msw/wx.rc"

The last relevant file is the resource file. In this simple example we don't add any of our own resources but you should always use a resource file that contains at least the line shown above. In later examples we add our own resources.

All that remains is for you to build and run the program.

Building wxWidgets Programs with MinGW

Location of wxWidgets library and include files

The wxWidgets distribution contains many samples and for all of the samples there are make files for all the different platforms that wxWidgets can use. Although this is a sensible way to generate programs since the user need not be concerned with specifying all the detail which determines what kind of target program will be generated, I must admit I found it a bit puzzling. There was also the disadvantage, as I perceived it anyway, that the build process had to specify where the include files and libraries where kept. I found that keeping the wxWidgets includes in the standard include location and the wxWidgets library in the standard library location to be more helpful. After building and installing the library I moved it, and the wx include directories, to the standard locations. On my Windows system this is in the MinGW tree, on my Linux system this was either in the /usr or /usr/local tree (usr/lib, /usr/include or /usr/local/lib, /usr/local/include).

The primary benefit of relocating the library and include files is that it removes one level of obfuscation which might confuse the beginner. That done I can now use this makefile to build the examples:

PROGRAM = basic
OBJECTS = ${PROGRAM}.o ${PROGRAM}_resources.o
RC = windres.exe
CC = g++

INCLUDES =

CCSW1 = --pipe -fvtable-thunks -c -D_X86_=1 -DWIN32 -D_WIN32 -DWINVER=0x0400 -D__WIN95__ \
        -D__GNUWIN32__ -D__WIN32__ -DSTRICT  -D__WXMSW__ -D__WINDOWS__\
        -Wall -fno-pcc-struct-return -O2 -fno-rtti -fno-exceptions   

CCSW2 = --pipe -fvtable-thunks -Wl,--subsystem,windows -mwindows 

LIBS  = -lwx -lxpm -lcomctl32 -ladvapi32 -lwsock32 -lole32 -loleaut32 -luuid 

RESSW = --include-dir c:/gcc-2.95.2-1/i386-mingw32msvc/include \
        --define __WIN32__ --define __WIN95__ --define __GNUWIN32__

.SUFFIXES: .o .cpp

all:    ${OBJECTS}
	$(CC) -o $(PROGRAM) ${OBJECTS} ${CCSW2} ${LIBS} 

.cpp.o: 
	$(CC) ${CCSW1} ${INCLUDES} -c -o $@ $<

${PROGRAM}_resources.o:
	$(RC) ${RESSW} ${PROGRAM}.rc $@

.PHONY : clean

clean:
	echo cleaning up
	rm $(OBJECTS)
	rm *.$$$$$$
	rm ${PROGRAM}.exe

To build the program:

  1. Create the source files in a single directory
    • basic.h
    • basic.cpp
    • basic_resources.rc
    • Makefile
  2. Run make in the directory where the files are stored
    • make
  3. Run the program
    • basic

The wxWidgets Classes Used

We used two classes: wxApp, and wxFrame from which we derived our own classes BasicApplication and BasicFrame. I am going to enlarge the detail of the two classes but you can also read the more complete description in the wxWidgets documentation.

wxApp

The wxApp class contains around 30+ accessible members but at this stage we don't need to look at wxApp in any detail. Later when we do some work with the wxWidgets event system we can pursue wxApp.

wxFrame

Since the work the wxFrame class does is rather more "visible" we might spend a short time looking at some of its properties.

wxFrame (
	wxWindow* parent, 
	wxWindowID id, 
	const wxString& title, 
	const wxPoint& pos = wxDefaultPosition, 
	const wxSize& size = wxDefaultSize, 
	long style = wxDEFAULT_FRAME_STYLE, 
	const wxString& name = _T("frame")
)

Our BasicFrame constructor provided for only four obvious parameters: a title, x and y position, and, width and height.

The wxFrame constructor has other parameters: a wxWindow pointer, a style, a name and a wxWindowID, the latter is an integer and if it is -1 the a default value is used. It might sometimes be useful to supply an ID of your own. The pointer points to a parent window, if there is one. In our case the pointer was NULL, there was no parent window. The name parameter can be supplied by the programmer and, like the ID parameter, may be useful if a frame is to be referred to.

The frame style can be a variety of styles:

Window Styles

  • wxDEFAULT_FRAME_STYLE Defined as wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BOX | wxSYSTEM_MENU | wxCAPTION.
  • wxICONIZE Display the frame iconized (minimized). Windows only.
  • wxCAPTION Puts a caption on the frame.
  • wxMINIMIZE Identical to wxICONIZE. Windows only.
  • wxMINIMIZE_BOX Displays a minimize box on the frame.
  • wxMAXIMIZE Displays the frame maximized. Windows only.
  • wxMAXIMIZE_BOX Displays a maximize box on the frame.
  • wxSTAY_ON_TOP Stay on top of other windows. Windows only.
  • wxSYSTEM_MENU Displays a system menu.
  • wxSIMPLE_BORDER Displays no border or decorations. GTK and Windows only.
  • wxRESIZE_BORDER Displays a resizeable border around the window (Unix only).
  • wxFRAME_FLOAT_ON_PARENT Causes the frame to be above the parent window in the z-order and not shown in the taskbar. Without this style, frames are created as top-level windows that may be obscured by the parent window, and frame titles are shown in the taskbar. Windows and GTK.
  • wxFRAME_TOOL_WINDOW Causes a frame with a small titlebar to be created; the frame title does not appear in the taskbar. Windows only.

A frame style is the OR of a one or more styles. In the absence of a style definition (as in our BasicFrame) the default applies, ie BasicFrame will have a minimize box, a maximize box, a system menu, a caption and will be resizable.

BasicFrame::BasicFrame( const wxChar *title, int xpos, int ypos, int width, int height )
: wxFrame( (wxFrame*) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height), wxSIMPLE_BORDER )

So that you can see the effect of the different styles modify the BasicFrame constructor so that a style is passed as an argument to the wxFrame constructor as shown here.

Amongst the two-dozen or so members of wxFrame are the methods:

  • CreateStatusBar
  • CreateToolBar
  • GetTitle
  • SetIcon
  • SetMenuBar
  • SetStatusBar
  • SetStatusText
  • SetToolBar
  • SetTitle

You will use most of these during the coming sessions but for now here is an exercise with the SetTitle and GetTitle member functions.

BasicFrame::BasicFrame( const wxChar *title, int xpos, int ypos, int width, int height )
: wxFrame( (wxFrame *) NULL, -1, title,
            wxPoint(xpos, ypos),
            wxSize(width, height),
            wxDEFAULT_FRAME_STYLE,
            _T("Fred")
        )
{
}

The constructor has been modified so that it passes a name to the wxFrame constructor. Now add this line:

frame->SetTitle(frame->GetTitle() + _T(" ") + frame->GetName());

to the BasicApplication::OnInit() function before the frame->Show(true) line.

Build and run the program and you will see the effect. Where does the GetName() method come from?

Summary

In this first session you have covered a fair piece of ground. You have seen the basic wxWidgets framework and might be getting some idea of the architecture. Don't forget to lookup references to the classes in the wxWidgets documentation. You may find it confusing at first but the exercise pays off well. I suggest also that when the opportunity arises (which is quite often) you should browse through the source code for wxWidgets. You will find lots of useful comments there and also start to get a grasp of what underlies this excellent package.