Multiplatform application development with wxWindows

Julian Smart, Robert Roebling, Vadim Zeitlin, Robin Dunn, et al

August 13th 2000

Contents

  • Acknowledgements
  • Introducing wxWindows
  • Installing wxWindows
  • wxWindows and C++
  • Getting started
  • Basic event handling
  • Working with frames
  • Working with toolbars
  • Basic controls
  • Common dialogs
  • Custom dialogs and resources
  • Drawing on device contexts
  • Handling input
  • Working with sizers
  • Images and bitmaps
  • The clipboard and drag-and-drop
  • Advanced controls
  • The document view framework
  • Managing scrolling
  • The multiple document interface
  • Adding printing to your application
  • Adding online help to your application
  • The wxString class
  • Data classes
  • Memory management and debugging
  • Using run-time class information
  • Advanced event handling
  • Interprocess communication
  • Working with databases
  • Working with files and streams
  • Handling application settings with wxConfig
  • Time, timers and idle processing
  • Multithreading your application
  • Perfecting your application
  • Platform-specific classes
  • Working with the HTML classes
  • An introduction to wxPython
  • wxBase: wxWindows without the GUI
  • Comparison with other toolkits
  • Further resources
  • References


Acknowledgements

We would like to acknowledge the help of the following people.

(Insert list of people here.)


Introducing wxWindows

The need for portability
Why wxWindows?
The history of wxWindows
How to use this book


The need for portability

Not so long ago, it seemed as though Microsoft was on course to take over the desktop for good with the Windows range of operating systems. Unix was retreating to server territory and had all but given up the fight against NT. Apple was sickening (in the non-derogatory sense of the word!) and it seemed almost common sense that the quirky Mac had had its day.

At the start of the new century, the picture has changed quite dramatically. Linux is advancing from its position of strength in the server market and is poised to make inroads on the desktop, where the high price of Windows gives it an advantage. Apple has made an impressive comeback and is revamping its own operating system. The embedded market continues to explode and has given rise to new niches for specialist operating systems. The keyword now is diversity, when the best guess of a few years was that Microsoft would conquer all. More than ever, application developers need to keep their options open and targeting one platform only can be a recipe for commercial (or open source) disaster.

In the light of this change in the computing landscape, cross-platform development (or multiplatform development as we call it in this book) has become quite a hot and sometimes bitterly controversial topic. There are a number of ways to achieve the goal of portability, and many tools and languages to choose from. However, it is still generally agreed wisdom that C++ is the language of choice for desktop applications that depend on speed, ease of delivery and compatibility with billions of lines of existing code. Plus, there are many hundreds of thousands of developers now experienced in C++ programming.

The purpose of this book is to give you (the developer or interested manager) a solid grounding in one increasingly popular multiplatform solution: wxWindows. wxWindows is an open source GUI toolkit that has been on the scene since 1993 and has reached a high degree of stability and functionality. It is available for Linux (and most other Unix variants), all desktop versions of Microsoft Windows, and Mac. Other ports are in progress.


Why wxWindows?

While wxWindows is labelled a GUI development toolkit, it is in fact much more than that and has many features that are useful for many aspects of application development. This has to be the case, since the whole of a wxWindows application needs to be portable to different platforms, and not just the GUI component. So wxWindows provides classes for working with files and streams, multithreading, management of application settings, interprocess communication, and much else.

wxWindows is open source, with a vibrant developer and user community, and may be used in any proprietary or non-proprietary project. wxWindows encompasses the whole spectrum of users from one-man software outfits to big-name companies such as Xerox, Lockheed-Martin, Pratt and Whitney, and Motorola; from computer science departments to medical research groups; from ecological research, to the telecommunications industry, and in a myriad of open source projects.

When you use wxWindows you tap into an astonishing talent pool, with contributors from a wide range of backgrounds. Many aspects of application development that you might otherwise have to laboriously code yourself have been encapsulated by these developers in easy-to-use classes that you can plug into your code. Since there are a lot of people subscribed to the mailing lists, you'll enjoy discussions not only about wxWindows but often other matters close to the hearts of both experienced and inexperienced developers. And hopefully, one day you'll join in the success of wxWindows and become a contributor yourself!


The history of wxWindows

wxWindows was started in 1992 at the Artificial Intelligence Applications Institute, University of Edinburgh, by Julian Smart. Julian was designing a kind of meta-CASE tool called Hardy which needed to run on Windows as well as X-based Unix workstations. The existing commercial cross-platform tools were deemed too expensive for an in-house experimental project, so the only alternative was to build one. wxWindows (w for Microsoft Windows, x for the X Windowing System) started off with support for Sun's XView and Microsoft's MFC 1.0, and AIAI allowed it to be released to the Internet. As it became clear that XView was doomed, a Motif port was written. Borland C++ users began to request a version that was not dependent on MFC, so the Windows port was rewritten to use the native Windows API. Over time, a small but enthusiastic community of wxWindows users was established and a mailing list set up. Many contributions and fixes were sent in. wxWindows gradually picked up more and more users from all over the world: academic, government, and corporate users who found that wxWindows offered a better product, and better support, than the commercial products they had looked at or used.

During 1995, Markus Holzem released his port of wxWindows to Xt, the X toolkit. This meant that software could be written that would work on X-based systems without the need for installing Motif, then still a commercial product.

In 1996, Julian left AIAI to pursue freelance consultancy, and there were few new releases. The seemingly unstoppable advance of Java was throwing some doubt on the future of C++ libraries. After many contributions, the wxWindows code was looking rather tired and in need of a serious rethink. At the start of 1997 it was make or break time - call it a day and move onto other things, or commit to re-engineering wxWindows with an API that was flexible enough for current and future user interface trends, with more sophisticated widgets, and making better use of C++. After a short debate, the effort was relaunched with Julian concentrating on the Windows port, and Markus on the combined Motif/Xt port, with both contributing to the common and generic parts. wxWindows 2 API ideas and code started to take shape.

During 1997 an effort to produce a standard Linux desktop environment was underway - GNOME. Its widget set was GTK+, built on top of X11 and it looked as though GTK+-based apps were to become the standard in the Linux universe. Its one major problem: GTK+ was C-based, and only a thin (and unportable) C++ wrapper existed for it. In August 1997, Wolfram Gloger made a suggestion that wxWindows 2 should be ported to GTK+ - Robert Roebling had initial reservations, but in general supported the idea. He became the prime mover for wxGTK and alphas were made available at the beginning of 1998. In May 1998 the Windows and GTK+ ports were merged and put into a CVS repository made available to all contributors to wxWindows: a decision that has accelerated the development effort tremendously. At this point Vadim Zeitlin became a prime mover on the Windows port and revamped much of the container and collection support.

Markus Holzem had to drop out of the wxWindows 2 effort in early 1998, but Julian Smart started a new wxMotif port. The idea of an Xt port was dropped, since there remain two possibilities for free Unix programming with wxWindows: wxGTK, and wxMotif using the Motif clone Lesstif.

In September 1998, Stefan Csomor started a new version of the wxMac 2 port based in part on Greg Whitehead's initial work. In 1999 wxMac became ready for prime-time and Stefan has made it ready for MacOS X.

Also in 1998, Vaclav Slavik burst onto the wxWindows scene with his exciting wxHTML module that can now provide applications with (to name but a few) HTML help, superb About boxes, and report viewing and printing facilities. Vaclav has also written an enhanced resource system for wxWindows based on XML, that supports many more wxWindows features than the old WXR-based system.

Since 1998 Robin Dunn has been completely rewriting the old Python/wxWindows marriage and now wxPython is another force to be reckoned with in the development community.

Development on wxWindows is concentrating on achieving more modularity, additional sophisticated GUI components, and compatibility with a wider range platforms. The wxStudio IDE project promises to make wxWindows development much easier and introduce wxWindows to people used to rapid application development environments under Microsoft Windows.


How to use this book

The chapters in this book are meant to be fairly independent, but as usual, the ordering reflects a progression from basic concepts to more advanced ones, so the first few chapters at least should be read consecutively for best effect.

Complete programs illustrating concepts in many of the chapters can be found in the accompanying CD-ROM, along with wxWindows itself and lots of extra, cool stuff.

We all hope that you enjoy reading this book and, most importantly, have fun using wxWindows to build great-looking, multiplatform applications!


Installing wxWindows

CONTENTS: Installing wxWindows (and what tools to use).

Installing wxWindows isn't too hard. Each platform has a different method, so we'll look at each major platform in turn.


Unix: GTK+ and Motif

The most simple case
The expert case
The most simple errors
The most simple program
Building wxGTK on OS/2
Building wxGTK on SGI
Create your configuration

The most simple case

If you are compile wxWindows on Linux for the first time and don't like to read install instructions, just do this in the base directory:

  ./configure --with-gtk
  make
  su <type root password>
  make install
  ldconfig
  exit
This is using the GTK+ port. If using the Motif port, type --with-motif instead of --with-gtk.

Afterwards you can continue with:

  make
  su <type root password>
  make install
  ldconfig
  exit
If you want to remove wxWindows on Unix you can do this:

  su <type root password>
  make uninstall
  ldconfig
  exit

The expert case

If you want to do some more serious cross-platform programming with wxWindows, such as for GTK and Motif, you can now build two complete libraries and use them concurrently. For this end, you have to create a directory for each build of wxWindows - you may also want to create different versions of wxWindows and test them concurrently. Most typically, this would be a version configured with --enable-debug_flag and one without. Note, that only one build can currently be installed, so you'd have to use a local version of the library for that purpose. For building three versions (one for GTK+, one for Motif and a debug GTK+ version) you'd do this:

  md buildmotif
  cd buildmotif
 ../configure --with-motif
  make
  cd ..

  md buildgtk
  cd buildgtk
  ../configure --with-gtk
  make
  cd ..

  md buildgtkd
  cd buildgtkd
  ../configure --with-gtk --enable-debug_flag
  make
  cd ..

The most simple errors

  • Configure reports, that you don't have GTK 1.2 installed although you are very sure you have. Well, you have installed it, but you also have another version of the GTK installed, which you may need to remove including other versions of glib (and its headers). Also, look for the PATH variable and check if it includes the path to the correct gtk-config! The check your LDPATH if it points to the correct library. There is no way to compile wxGTK if configure doesn't pass this test as all this test does is compile and link a GTK program.
  • You get errors during compilation: The reason is that you probably have a broken compiler, which includes almost everything that is called gcc. If you use gcc 2.8 you have to disable optimsation as the compiler will give up with an internal compiler error.You get immediate segfault when starting any sample or application: This is either due to having compiled the library with different flags or options than your program - typically you might have the __WXDEBUG__ option set for the library but not for your program - or due to using a broken compiler (and its optimisation) such as GCC 2.8.

The most simple program

Now create your super-application myfoo.app and compile anywhere with:

  gcc myfoo.cpp `wx-config --libs --cflags` -o myfoo
General

The Unix variants of wxWindows use GNU configure. If you have problems with your make use GNU make instead.

If you have general problems with installation, visit Robert Roebling's homepage at

  http://wesley.informatik.uni-freiburg.de/~wxxt
for the latest information. If you still don't have any success, please send a bug report to one of the mailing lists.

Libraries needed

wxWindows/GTK requires the GTK+ library to be installed on your system. It has to be a stable version, preferebly version 1.2.3.

You can get the newest version of the GTK+ from the GTK homepage at:

  http://www.gtk.org
wxWindows/Gtk requires a thread library and X libraries known to work with threads. This is the case on all commercial Unix-Variants and all Linux-Versions that are based on glibc 2 except RedHat 5.0 which is broken in many aspects. As of writing this, these Linux distributions have correct glibc 2 support:

  • RedHat 5.1
  • Debian 2.0
  • Stampede
  • DLD 6.0
  • SuSE 6.0
You can disable thread support by running

./configure "--disable-threads"
make
su <type root password>
make install
ldconfig
exit

Building wxGTK on OS/2

Please send comments and question about the OS/2 installation to Andrea Venturoli <a.ventu@flashnet.it> and patches to the wxWindows mailing list.

You'll need OS/2 Warp (4.00FP6), X-Free86/2 (3.3.3 or newer), GTK+ (1.2.5 or newer), emx (0.9d fix 1), flex (2.5.4), yacc (1.8), korn shell (5.2.13), Autoconf (2.13), GNU file utilities (3.6), GNU text utilities (1.3), GNU shell utilites (1.12), m4 (1.4), sed (2.05), grep (2.0), Awk (3.0.3), GNU Make (3.76.1).

Open an OS/2 prompt and switch to the directory above. First set some global environment variables we need:

  SET CXXFLAGS=-Zmtd -D__ST_MT_ERRNO__
  SET CFLAGS=-Zmtd -D__ST_MT_ERRNO__
  SET OSTYPE=OS2X
  SET COMSPEC=sh
  \end{verbatim}

Notice you can choose whatever you want, if you don't like OS2X.

Now, run autoconf in the main directory and in the samples, demos
and utils subdirectory. This will generate the OS/2 specific
versions of the configure scripts. Now run

\begin{verbatim}
    configure --with-gtk
as described above.

If you have pthreads library installed, but have a gtk version which does not yet support threading, you need to explicitly diable threading by using the option --disable-threads.

Note that configure assumes your flex will generate files named "lexyy.c", not "lex.yy.c". If you have a version which does generate "lex.yy.c", you need to manually change the generated makefile.

Building wxGTK on SGI

Using the SGI native compilers, it is recommended that you also set CFLAGS and CXXFLAGS before running configure. These should be set to:

  CFLAGS="-mips3 -n32"
  CXXFLAGS="-mips3 -n32"
This is essential if you want to use the resultant binaries on any other machine than the one it was compiled on. If you have a 64-bit machine (Octane) you should also do this to ensure you don't accidently build the libraries as 64bit (which is untested).

The SGI native compiler support has only been tested on Irix 6.5.

Create your configuration

Usage:

    ./configure options
If you want to use system's C and C++ compiler, set environment variables CC and CCC as

  setenv CC cc
  setenv CCC CC
  ./configure options
to see all the options please use:

  ./configure --help
The basic philosophy is that if you want to use different configurations, like a debug and a release version, or use the same source tree on different systems, you have only to change the environment variable OSTYPE. (Sadly this variable is not set by default on some systems in some shells - on SGI's for example). So you will have to set it there. This variable HAS to be set before starting configure, so that it knows which system it tries to configure for.

Configure (and sometimes make) will complain if the system variable OSTYPE has not been defined.

General options

Given below are the commands to change the default behaviour, i.e. if it says "--disable-threads" it means that threads are enabled by default.

Normally, you won't have to choose a toolkit, because when you download wxGTK, it will default to --with-gtk etc. But if you use all of our CVS repository you have to choose a toolkit. You must do this by running configure with either of:

    --without-gtk            Don't use the GIMP ToolKit (GTK)

    --with-motif             Use either Motif or Lesstif
                             Configure will look for both.
The following options handle the kind of library you want to build.

    --disable-threads       Compile without thread support.

    --disable-shared        Do not create shared libraries.

    --enable-static         Create static libraries.

    --disable-optimise	    Do not optimise the code. Can
                            sometimes be useful for debugging
                            and is required on some architectures
                            such as Sun with gcc 2.8.X which
                            and otherwise produce segvs.

    --enable-profile        Add profiling info to the object
                            files. Currently broken, I think.

    --enable-no_rtti        Enable compilation without creation of
                            C++ RTTI information in object files.
                            This will speed-up compilation and reduce
                            binary size.

    --enable-no_exceptions  Enable compilation without creation of
                            C++ exception information in object files.
                            This will speed-up compilation and reduce
                            binary size. Also fewer crashes during the
                            actual compilation...

    --enable-no_deps        Enable compilation without creation of
                            dependency information.

    --enable-permissive     Enable compilation without creation of
                            giving erros as soon as you compile with
                            Solaris' ANSI-defying headers.

    --enable-mem_tracing    Add built-in memory tracing.

    --enable-dmalloc        Use the dmalloc memory debugger.
                            Read more at www.letters.com/dmalloc/

    --enable-debug_info	    Add debug info to object files and
                            executables for use with debuggers
                            such as gdb (or its many frontends).

    --enable-debug_flag	    Define __DEBUG__ and __WXDEBUG__ when
                            compiling. This enable wxWindows' very
                            useful internal debugging tricks (such
                            as automatically reporting illegal calls)
                            to work. Note that program and library
                            must be compiled with the same debug
                            options.

Feature Options

When producing an executable that is linked statically with wxGTK you'll be surprised at its immense size. This can sometimes be drastically reduced by removing features from wxWindows that are not used in your program. The most relevant such features are

    --with-odbc             Enables ODBC code. This is disabled
                            by default because iODBC is under the
                            L-GPL license.

    --without-libpng	    Disables PNG image format code.

    --without-libjpeg	    Disables JPEG image format code.

    --without-libtiff	    Disables TIFF image format code.

    --disable-pnm		    Disables PNM image format code.

    --disable-gif		    Disables GIF image format code.

    --disable-pcx		    Disables PCX image format code.

    --disable-resources     Disables the use of *.wxr type
                            resources.

    --disable-threads       Disables threads. Will also
                            disable sockets.

    --disable-sockets       Disables sockets.

    --disable-dnd           Disables Drag'n'Drop.

    --disable-clipboard     Disables Clipboard.

    --disable-serial        Disables object instance serialiasation.

    --disable-streams       Disables the wxStream classes.

    --disable-file          Disables the wxFile class.

    --disable-textfile      Disables the wxTextFile class.

    --disable-intl          Disables the internationalisation.

    --disable-validators    Disables validators.

    --disable-accel         Disables accel.
Apart from disabling certain features you can very often "strip" the program of its debugging information resulting in a significant reduction in size.

Compiling

The following must be done in the base directory (e.g. /wxGTK or /wxWin or whatever)

Now the makefiles are created (by configure) and you can compile the library by typing:

    make
make yourself some coffee, as it will take some time. On an old 386SX possibly two weeks. During compilation, you'll get a few warning messages depending in your compiler.

If you want to be more selective, you can change into a specific directiry and type "make" there.

Then you may install the library and it's header files under /usr/local/include/wx and /usr/local/lib respectively. You have to log in as root (i.e. run "su" and enter the root password) and type

        make install
You can remove any traces of wxWindows by typing

        make uninstall
If you want to save disk space by removing unnecessary object-files:

        make clean
in the various directories will do the work for you.

Creating a new Project

1) The first way uses the installed libraries and header files automatically using wx-config

gcc myfoo.cpp `wx-config --cflags --libs` -o myfoo
Using this way, a make file for the minimal sample would look like this

CC = gcc

minimal: minimal.o
    $(CC) -o minimal minimal.o `wx-config --libs`

minimal.o: minimal.cpp mondrian.xpm
    $(CC) `wx-config --cflags` -c minimal.cpp -o minimal.o

clean:
    rm -f *.o minimal
This is certain to become the standard way unless we decide to sitch to tmake.

2) The other way creates a project within the source code directories of wxWindows. For this endeavour, you'll need GNU autoconf version 2.14 and add an entry to your Makefile.in to the bottom of the configure.in script and run autoconf and configure before you can type make.


Windows


Mac

We don't have information about Mac installation at this time.


wxWindows and C++

What kind of C++ constructs wxWindows uses and doesn't use, and a little introduction to some important classes such as wxString. Why STL isn't used within wxWindows.


Getting started

Getting started: Hello World. Introduces app class, frames, menus, status bar, message box.


Basic event handling

Introduction
How events are processed
Pluggable event handlers
Window identifiers
Event macros summary


Introduction

In most cases, wxWindows uses the concept of event tables to catch user input.

An event table is placed in an implementation file to tell wxWindows how to map events to member functions. These member functions are not virtual functions, but they are all similar in form: they take a single wxEvent-derived argument, and have a void return type.

Here's an example of an event table.

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  EVT_MENU    (wxID_EXIT, MyFrame::OnExit)
  EVT_MENU    (DO_TEST,   MyFrame::DoTest)
  EVT_SIZE    (           MyFrame::OnSize)
  EVT_BUTTON  (BUTTON1,   MyFrame::OnButton1)
END_EVENT_TABLE()
The first two entries map menu commands to two different member functions. The EVT_SIZE macro doesn't need a window identifier, since normally you are only interested in the current window's size events. (In fact you could intercept a particular window's size event by using EVT_CUSTOM(wxEVT_SIZE, id, func).)

The EVT_BUTTON macro demonstrates that the originating event does not have to come from the window class implementing the event table - if the event source is a button within a panel within a frame, this will still work, because event tables are searched up through the hierarchy of windows. In this case, the button's event table will be searched, then the parent panel's, then the frame's.

As mentioned before, the member functions that handle events do not have to be virtual. Indeed, the member functions should not be virtual as the event handler ignores that the functions are virtual, i.e. overriding a virtual member function in a derived class will not have any effect. These member functions take an event argument, and the class of event differs according to the type of event and the class of the originating window. For size events, wxSizeEvent is used. For menu commands and most control commands (such as button presses), wxCommandEvent is used. When controls get more complicated, then specific event classes are used, such as wxTreeEvent for events from wxTreeCtrl windows.

As well as the event table in the implementation file, there must be a DECLARE_EVENT_TABLE macro in the class definition. For example:

class MyFrame: public wxFrame {

  DECLARE_DYNAMIC_CLASS(MyFrame)

public:
  ...
  void OnExit(wxCommandEvent& event);
  void OnSize(wxSizeEvent& event);
protected:
  int       m_count;
  ...
  DECLARE_EVENT_TABLE()
};


How events are processed

When an event is received from the windowing system, wxWindows calls wxEvtHandler::ProcessEvent on the first event handler object belonging to the window generating the event.

It may be noted that wxWindows' event processing system implements something very close to virtual methods in normal C++, i.e. it is possible to alter the behaviour of a class by overriding its event handling functions. In many cases this works even for changing the behaviour of native controls. For example it is possible to filter out a number of key events sent by the system to a native text control by overriding wxTextCtrl and defining a handler for key events using EVT_KEY_DOWN. This would indeed prevent any key events from being sent to the native control - which might not be what is desired. In this case the event handler function has to call Skip() so as to indicate that the search for the event handler should continue.

To summarize, instead of explicitly calling the base class version as you would have done with C++ virtual functions (i.e. wxTextCtrl::OnChar()), you should instead call wxEvent::Skip.

In practice, this would look like the following if the derived text control only accepts 'a' to 'z' and 'A' to 'Z':

void MyTextCtrl::OnChar(wxKeyEvent& event)
{
    if ( isalpha( event.KeyCode() ) )
    {
       // key code is within legal range. we call event.Skip() so the
       // event can be processed either in the base wxWindows class
       // or the native control.

       event.Skip();
    }
    else
    {
       // illegal key hit. we don't call event.Skip() so the
       // event is not processed anywhere else.

       wxBell();
    }
}
The normal order of event table searching by ProcessEvent is as follows:

  1. If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled) the function skips to step (6).
  2. If the object is a wxWindow, ProcessEvent is recursively called on the window's wxValidator. If this returns TRUE, the function exits.
  3. SearchEventTable is called for this event handler. If this fails, the base class table is tried, and so on until no more tables exist or an appropriate function was found, in which case the function exits.
  4. The search is applied down the entire chain of event handlers (usually the chain has a length of one). If this succeeds, the function exits.
  5. If the object is a wxWindow and the event is a wxCommandEvent, ProcessEvent is recursively applied to the parent window's event handler. If this returns TRUE, the function exits.
  6. Finally, ProcessEvent is called on the wxApp object.

Pay close attention to Step 5. People often overlook or get confused by this powerful feature of the wxWindows event processing system. To put it a different way, events derived either directly or indirectly from wxCommandEvent will travel up the containment hierarchy from child to parent until an event handler is found that doesn't call event.Skip(). Events not derived from wxCommandEvent are sent only to the window they occurred in and then stop.

Typically events that deal with a window as a window (size, motion, paint, mouse, keyboard, etc.) are sent only to the window. Events that have a higher level of meaning and/or are generated by the window itself, (button click, menu select, tree expand, etc.) are command events and are sent up to the parent to see if it is interested in the event.

Note that your application may wish to override ProcessEvent to redirect processing of events. This is done in the document/view framework, for example, to allow event handlers to be defined in the document or view. To test for command events (which will probably be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for efficiency, instead of using the slower run-time type system.

As mentioned above, only command events are recursively applied to the parents event handler. As this quite often causes confusion for users, here is a list of system events which will not get sent to the parent's event handler:

wxEvent | The event base class
wxActivateEvent | A window or application activation event
wxCloseEvent | A close window or end session event
wxEraseEvent | An erase background event
wxFocusEvent | A window focus event
wxKeyEvent | A keypress event
wxIdleEvent | An idle event
wxInitDialogEvent | A dialog initialisation event
wxJoystickEvent | A joystick event
wxMenuEvent | A menu event
wxMouseEvent | A mouse event
wxMoveEvent | A move event
wxPaintEvent | A paint event
wxQueryLayoutInfoEvent | Used to query layout information
wxSizeEvent | A size event
wxScrollWinEvent | A scroll event sent by a scrolled window (not a scroll bar)
wxSysColourChangedEvent | A system colour change event
wxUpdateUIEvent | A user interface update event

In some cases, it might be desired by the programmer to get a certain number of system events in a parent window, for example all key events sent to, but not used by, the native controls in a dialog. In this case, a special event handler will have to be written that will override ProcessEvent() in order to pass all events (or any selection of them) to the parent window.


Pluggable event handlers

In fact, you don't have to derive a new class from a window class if you don't want to. You can derive a new class from wxEvtHandler instead, defining the appropriate event table, and then call wxWindow::SetEventHandler (or, preferably, wxWindow::PushEventHandler) to make this event handler the object that responds to events. This way, you can avoid a lot of class derivation, and use the same event handler object to handle events from instances of different classes. If you ever have to call a window's event handler manually, use the GetEventHandler function to retrieve the window's event handler and use that to call the member function. By default, GetEventHandler returns a pointer to the window itself unless an application has redirected event handling using SetEventHandler or PushEventHandler.

One use of PushEventHandler is to temporarily or permanently change the behaviour of the GUI. For example, you might want to invoke a dialog editor in your application that changes aspects of dialog boxes. You can grab all the input for an existing dialog box, and edit it 'in situ', before restoring its behaviour to normal. So even if the application has derived new classes to customize behaviour, your utility can indulge in a spot of body-snatching. It could be a useful technique for on-line tutorials, too, where you take a user through a serious of steps and don't want them to diverge from the lesson. Here, you can examine the events coming from buttons and windows, and if acceptable, pass them through to the original event handler. Use PushEventHandler/PopEventHandler to form a chain of event handlers, where each handler processes a different range of events independently from the other handlers.


Window identifiers

Window identifiers are integers, and are used to uniquely determine window identity in the event system (though you can use it for other purposes). In fact, identifiers do not need to be unique across your entire application just so long as they are unique within a particular context you're interested in, such as a frame and its children. You may use the wxID_OK identifier, for example, on any number of dialogs so long as you don't have several within the same dialog.

If you pass -1 to a window constructor, an identifier will be generated for you, but beware: if things don't respond in the way they should, it could be because of an id conflict. It is safer to supply window ids at all times. Automatic generation of identifiers starts at 1 so may well conflict with your own identifiers.

The following standard identifiers are supplied. You can use wxID_HIGHEST to determine the number above which it is safe to define your own identifiers. Or, you can use identifiers below wxID_LOWEST.

#define wxID_LOWEST             4999

#define wxID_OPEN               5000
#define wxID_CLOSE              5001
#define wxID_NEW                5002
#define wxID_SAVE               5003
#define wxID_SAVEAS             5004
#define wxID_REVERT             5005
#define wxID_EXIT               5006
#define wxID_UNDO               5007
#define wxID_REDO               5008
#define wxID_HELP               5009
#define wxID_PRINT              5010
#define wxID_PRINT_SETUP        5011
#define wxID_PREVIEW            5012
#define wxID_ABOUT              5013
#define wxID_HELP_CONTENTS      5014
#define wxID_HELP_COMMANDS      5015
#define wxID_HELP_PROCEDURES    5016
#define wxID_HELP_CONTEXT       5017

#define wxID_CUT                5030
#define wxID_COPY               5031
#define wxID_PASTE              5032
#define wxID_CLEAR              5033
#define wxID_FIND               5034
#define wxID_DUPLICATE          5035
#define wxID_SELECTALL          5036

#define wxID_FILE1              5050
#define wxID_FILE2              5051
#define wxID_FILE3              5052
#define wxID_FILE4              5053
#define wxID_FILE5              5054
#define wxID_FILE6              5055
#define wxID_FILE7              5056
#define wxID_FILE8              5057
#define wxID_FILE9              5058

#define wxID_OK                 5100
#define wxID_CANCEL             5101
#define wxID_APPLY              5102
#define wxID_YES                5103
#define wxID_NO                 5104
#define wxID_STATIC             5105

#define wxID_HIGHEST            5999


Event macros summary

Generic event table macros

EVT_CUSTOM(event, id, func) | Allows you to add a custom event table entry by specifying the event identifier (such as wxEVT_SIZE), the window identifier, and a member function to call.
EVT_CUSTOM_RANGE(event, id1, id2, func) | The same as EVT_CUSTOM, but responds to a range of window identifiers.
EVT_COMMAND(id, event, func) | The same as EVT_CUSTOM, but expects a member function with a wxCommandEvent argument.
EVT_COMMAND_RANGE(id1, id2, event, func) | The same as EVT_CUSTOM_RANGE, but expects a member function with a wxCommandEvent argument.

Macros listed by event class

The documentation for specific event macros is organised by event class. Please refer to these sections for details.

wxActivateEvent | The EVT_ACTIVATE and EVT_ACTIVATE_APP macros intercept activation and deactivation events.
wxCommandEvent | A range of commonly-used control events.
wxCloseEvent | The EVT_CLOSE macro handles window closure called via wxWindow::Close.
wxDropFilesEvent | The EVT_DROP_FILES macros handles file drop events.
wxEraseEvent | The EVT_ERASE_BACKGROUND macro is used to handle window erase requests.
wxFocusEvent | The EVT_SET_FOCUS and EVT_KILL_FOCUS macros are used to handle keyboard focus events.
wxKeyEvent | EVT_CHAR and EVT_CHAR_HOOK macros handle keyboard input for any window.
wxIdleEvent | The EVT_IDLE macro handle application idle events (to process background tasks, for example).
wxInitDialogEvent | The EVT_INIT_DIALOG macro is used to handle dialog initialisation.
wxListEvent | These macros handle wxListCtrl events.
wxMenuEvent | These macros handle special menu events (not menu commands).
wxMouseEvent | Mouse event macros can handle either individual mouse events or all mouse events.
wxMoveEvent | The EVT_MOVE macro is used to handle a window move.
wxPaintEvent | The EVT_PAINT macro is used to handle window paint requests.
wxScrollEvent | These macros are used to handle scroll events from wxScrollBar, wxSlider,and wxSpinButton.
wxSizeEvent | The EVT_SIZE macro is used to handle a window resize.
wxSplitterEvent | The EVT_SPLITTER_SASH_POS_CHANGED, EVT_SPLITTER_UNSPLIT and EVT_SPLITTER_DOUBLECLICKED macros are used to handle the various splitter window events.
wxSysColourChangedEvent | The EVT_SYS_COLOUR_CHANGED macro is used to handle events informing the application that the user has changed the system colours (Windows only).
wxTreeEvent | These macros handle wxTreeCtrl events.
wxUpdateUIEvent | The EVT_UPDATE_UI macro is used to handle user interface update pseudo-events, which are generated to give the application the chance to update the visual state of menus, toolbars and controls.


Working with frames

The humble wxFrame, menubars, etc. Should the toolbar chapter be merged with this one?


Working with toolbars

Working with toolbars.


Basic controls

This chapter deals with the most fundamental controls (or widgets) that you will use in your application.


Common dialogs

In which common dialogs, such as file and colour selectors, are described.


Custom dialogs and resources

wxDialog introduced, and how XML resources work.


Drawing on device contexts

The concept of device contexts
Drawing into windows
Querying the update region


The concept of device contexts

Device contexts, commonly referred as DCs, represent more or less anything you can draw into, i.e. a window, a bitmap, the screen, a printer, a Postscript file, most recently even an SVG file. There is one abstract base class (wxDC) which defines the interface for all other classes so that drawing code for one device context can be used for all others as well - with certain limitation as the hardware specifies (e.g. you cannot read a pixel from a printer).


Drawing into windows

Let's start with the most simple case: you want to draw a line in a window. Or rather not the window, but its client area, the usually white or grey large area that is surrounded by the window's decorations such as its border which you normally would not want to draw over.

In addition to defining classes that represent devices, wxWindows has a few of classes that define colours and so-called pens and brushes. A pen is used for drawing lines (which can be a curve or a rectangle) whereas brushes are used to paint areas, such as a filled rectangle or a filled circle. Indeed, you can use both at the same time for drawing a rectangle which is both filled and has a border. If you want to draw a red rectangle with a black border, you will do this:

void MyWindow::DrawSomething()
{
    wxClientDC dc(this);

    dc.SetPen( *wxBLACK_PEN );
    dc.SetBrush( *wxRED_BRUSH );

    dc.DrawRectangle( 0, 0, 100, 100 );
}
If you want to draw a rectangle without any border, you can use the special oen wxTRANSPARENT_PEN, if the rectangle is not supposed to be filled with any colour, you use the special brush wxTRANSPARENT_BRUSH. When using both these special classes, you could draw an invisible rectangle like this:

void MyWindow::DrawNothing()
{
    wxClientDC dc(this);

    dc.SetPen( *wxTRANSPARENT_PEN );
    dc.SetBrush( *wxTRANSPARENT_BRUSH );

    dc.DrawRectangle( 0, 0, 100, 100 );
}
Now what happens when you window gets obscured by another window and then returns to the surface again? The rectangle will not appear again because a window does not remember what has been drawn into it. Instead, your program has to remember what to draw and where and it will receive a so called wxPaintEvent indicating that some region has been unobscured and needs repainting. In order to catch such an event so that you can react appropriately to it, you will have to set up an event handler like this:

BEGIN_EVENT_TABLE(MyWindow, wxWindow)
    EVT_PAINT  (MyWindow::OnPaint)
END_EVENT_TABLE()

void MyWindow::OnPaint( wxPaintEvent &event )
{
    wxPaintDC dc(this);

    dc.SetPen( *wxBLACK_PEN );
    dc.SetBrush( *wxRED_BRUSH );

    dc.DrawRectangle( 0, 0, 100, 100 );
}
Note that this time, you have to use a wxPaintDC as these are used in connection with wxPaintEvents. Note also, that every such handler has to use a wxPaintDC even of you (for the moment) don't draw anything. If there is no such wxPaintDC, your program will not work under Windows.

One difference between a wxPaintDC and a wxClientDC is that the wxPaintDC always sets a clipping region to the region of the window that was unobscured with the effect that all drawing commands will be clipped to that region. This leads to a reduction of flicker as only those areas of the window get redrawn, which actually need to get redrawn.


Querying the update region

Call me lazy:

BEGIN_EVENT_TABLE(MyWindow, wxWindow)
    EVT_PAINT  (MyWindow::OnPaint)
END_EVENT_TABLE()

void MyWindow::OnPaint( wxPaintEvent &event )
{
    wxPaintDC dc(this);

    if (IsExposed( 0, 0, 100, 100))
    {
        dc.SetPen( *wxBLACK_PEN );
        dc.SetBrush( *wxRED_BRUSH );

        dc.DrawRectangle( 0, 0, 100, 100 );
    }
}


Handling input

Handling input from keyboard, mouse and joystick.


Working with sizers

wxSizer and friends.


Images and bitmaps

The basics of images and bitmaps
wxImage built-in features


The basics of images and bitmaps

Both wxImage and wxBitmap represent what would commonly be referred as a photo with a given number of pixels - in contrast to a drawing consisting of a collection of lines, curves, circles, squares etc.

The difference between a wxImage and a wxBitmap is that wxImage is a platform and screen independent representation of an image - every pixel is always represented by three bytes, one for red, one for green and one for blue, thus yielding the classical RGB acronym. Due to the simplicity of wxImage, you will do all kinds of image manipulation with this class, this includes loading images in various formats such as GIF, TIFF or JPEG (these and some more are supported by wxWindows without further work), analyizing the image in terms of colour usage etc and applying filters to the image for higher-level manipulation, such as blurring, sharpening etc.

The problem with wxImage is that you cannot draw it, i.e. its destiny is to live its shadow life in memory, without ever being seen by man. If you ever want to draw an image to screen, you have to convert it to a wxBitmap first, typically, this will look like this:

    wxImage image( 200, 200 );
    wxBitmap bitmap( image.ConvertToBitmap() );

    wxClientDC dc( this )
    dc.DrawBitmap( bitmap );
Note, that such as image conversion is an extremely expensive operation and you are very well advised to avoid having to call this routine more than absolutely required. In practice, you should not do this in a paint event handler, for instance.

There is one more thing you can do with a wxBitmap: you can draw into it like you would do with a window. All you need to do is set up a proper device context (DC) for it and ensure that you clean up the DC correctly afterwards:

    wxBitmap bitmap( 200, 200 );

    wxMemoryDC dc;
    dc.SelectObject( bitmap );

    dc.SetPen( *wxBLACK_PEN );
    dc.DrawLine( 0, 0, 199, 199 );

    dc.SelectObject( wxNullBitmap );


wxImage built-in features

You can save it, load it, get access to it, assign it a mask colour, turn it around, mirror it.


The clipboard and drag-and-drop

In which the murky workings of data transfer are ably described by One Who Knows.


Advanced controls

This chapter looks at the following advanced wxWindows controls:

  • wxListCtrl
  • wxTreeCtrl
  • wxNotebook
  • wxSplitterWindow
  • wxSashWindow
  • wxWizard
  • wxCalCtrl


The document view framework

This chapter describes the document/view framework and in what situations it can be useful.


Managing scrolling

Scrolling can be hard. Here's how to do it.


The multiple document interface

MDI.


Adding printing to your application

The joys of printing.


Adding online help to your application

The varieties of help you can add to your masterwork.


The wxString class

A rather important class explained, together with how internationalisation works.


Data classes

Important collection and container classes in wxWindows.


Memory management and debugging

Memory management, debugging, wxLog, ...


Using run-time class information

CLASSINFO and friends.


Advanced event handling

This chapter explores the wxWindows event system in more detail, and shows you how to create your own event classes.


Interprocess communication

wxSocket, wxIPC, protocols...


Working with databases

Using databases in wxWindows. This chapter mainly covers the wxDb ODBC classes, but should also mention other cross-platform libraries such as Xbase. And perhaps a quick mention of wxExpr for very simple data storage needs.


Working with files and streams

All about the file and stream handling facilities in wxWindows.


Handling application settings with wxConfig

Using the wxConfig family of classes to save and restore application settings.


Time, timers and idle processing

Time, timers and idle processing.


Multithreading your application

Multithreading.


Perfecting your application

Finishing touches: UI update, splash screen, about box, managing registration, help files (see specific chapter), making an installation.


Platform-specific classes

Metafiles, OLE automation, GNOME integration, taskbar, ...


Working with the HTML classes

The coolness of wxHTML.


An introduction to wxPython

wxPython.


wxBase: wxWindows without the GUI

All about wxBase.


Comparison with other toolkits

In which we show the world how wonderful wxWindows is compared with the competition. But ever so modestly.

Actually, this chapter should be full of helpful tips for converting one's knowledge/apps from other toolkits such as MFC.


Further resources

A compendium of external resources, such as:

  • wxTTS
  • Xbase


References