Current Articles | RSS Feed
If you develop GUI applications, you probably know what you want from a toolkit or framework. Chances are that the ability to build apps that run on multiple platforms is high on the list, along with ease of use and deployment. Those are among the strong points of wxWidgets, an open source library designed to make it easy to create cross-platform GUI applications.
wxWidgets is implemented in C++, but it offers bindings for C, Python, PHP, .Net, Java, and many more. Code developed with wxWidgets can be compiled with compilers from Microsoft, Watcom, Borland, and MinGW, among others. Software built with wxWidgets can run on Windows, Mac OS X, iOS, Linux, Unix (any Unix that supports GTK+, X11, and/or Motif), and a few obsolete operating systems. Technically speaking, wxWidgets easily generates PostScript on Unix systems, supports Multiple Document Interface (MDI), and generates DLLs on Windows and dynamic libs on Unix(-like) systems. All that, and it has great documentation.
Another thing that makes wxWidgets attractive is the wxWidgets License, which is OSI-approved, making it officially free software, but the license is more liberal than the GPL. Well-known applications written with wxWidgets include aMule, Audacious, Filezilla, and TortoiseCVS.
The environment I work in includes a CentOS 6.2 64-bit machine with the gcc 4.x compiler, and that's the platform I'll use for the examples here. Despite wxWidgets' portability, all toolkits have some platform-specific aspects. CentOS offers wxWidgets integrated with the GNOME Toolkit as wxGTK and the respective -devel libraries; you can install them on CentOS by running yum install wxGTK*. If you'd rather compile wxWidgets from source, you can download it from the official FTP server, which offers documentation, binaries, tools, and older versions. I chose version 2.9.3, the most current release to date. The download site shows the care the authors take to satisfy developers, regardless of platform: It offers various archive formats and up-to-date documentation. The unpacked archive takes around 120MB on my system.
yum install wxGTK*
Before you start using wxWidgets, have a look at the project's wiki, which offers valuable information from various contributors. The wiki recommends using GTK with wxWidgets on Linux; you can, should you choose, use the packages from your distribution's repository, as I just mentioned above. I wanted to explore the source tree a little, so I ran the classic commands ./configure <options> && make && sudo make install. Here it's almost mandatory to first use configure's --help option first, to see the myriad of options to choose from. I went with the default install location (/usr/local) and had to install the GTK development libraries before compiling and installing.
./configure <options> && make && sudo make install
--help
A final point regarding installation: You might need some patience if your development box is underpowered. Since the tree is pretty hefty, compilation might take a while. Remember to run ldconfig and modify LD_LIBRARY_PATH after compilation and installation to inform the system about the newly installed libraries.
We'll start exploring wxWidgets by using wxGTK, since we agreed that's the choice to make when it comes to development on Linux. I won't talk about all the languages the toolkit supports, because I don't know them all and because that would take a lot of space. I'll focus on C++, as it's the language wxWidgets is actually implemented in.
To include the wxWidgets libraries in your C++ program, specify #include <wx/wx.h>. Since we're talking about a pretty big-sized library, you probably want to drastically cut compilation time, especially if your compiler supports precompiled headers. gcc, especially since 4.x, has improved precompiled headers support, so you might want to use it; the command to compile headers is g++ -c header.h -o header.h.gch. The documentation suggests the following code be placed before any other includes, should you use precompiled header files:
#include <wx/wx.h>
g++ -c header.h -o header.h.gch
#include <wx/wxprec.h>#ifdef __BORLANDC__#pragma hdrstop#endif#ifndef WX_PRECOMP// Include your minimal set of headers here, or wx.h#include <wx/wx.h>#endif
However, there are some downsides to using precompiled headers. Though you gain by having faster compile times, you lose by needing to include more header files than you normally would. That means changing a header like wx/wx.h that is used everywhere requires more recompilations. The solution to this would be to use conditional compilation, which basically means that you are using #ifdef directives so the resulting binary is different, depending on the platform you're using.
wx/wx.h
#ifdef
wxWidgets provides helper classes, which, as the name implies, are classes that are created to help developers work with elements like XML, database access, networking, or strings. And though this is an article about creating GUI applications, I will start illustrating how to program with wxWidgets with a simple, console-only "Hello, world!" program.
#include <wx/string.h>int main(int argc, char **argv){ wxPuts(wxT("Hello, world!"));}
It's always a good idea to look inside any header file you're going to use in order to get accustomed to the library. string.h includes all the functionalities you would expect from it, including, but not limited to, comparing strings, getting a string's length, and concatenation.
Another useful header is utils.h, which, for Unix(-like) system users, include the wxShell() function. You might be able to guess what it does:
#include <wx/string.h>#include <wx/utils.h>int main(int argc, char **argv){ wxShell(wxT("ls -lha")); //You will get the contents of the current directory}
Other useful functions here include wxGetHomeDir(), wxGetFreeMemory(), and wxGetOsDescription().
Sooner or later you will need date and time functions. The header for that helper class is datetime.h, and here's a quick example:
#include <wx/datetime.h>int main(int argc, char **argv){ wxDateTime now = wxDateTime::Now(); wxPrintf(wxT(" Tokyo: %s"), now.Format(wxT("%a %T"), wxDateTime::GMT9).c_str()); wxPrintf(wxT(" Moscow: %s"), now.Format(wxT("%a %T"), wxDateTime::MSD).c_str()); wxPrintf(wxT("Bucharest: %s"), now.Format(wxT("%a %T"), wxDateTime::EEST).c_str()); wxPrintf(wxT(" London: %s"), now.Format(wxT("%a %T"), wxDateTime::WEST).c_str()); wxPrintf(wxT("New York: %s"), now.Format(wxT("%a %T"), wxDateTime::EDT).c_str());}
Play around and try different features, headers, and arguments; that's the best way to learn any new technology.
Next, it's time to start using wxWidgets for what it does best: graphical applications. The toolkit offers several ways of doing things, depending on the developer's preferences. I like to split the source into as many files as possible, and for that I refer you to ZetCode, which seems to take the same approach.
Our first simple application displays a window with a title, which in our example is "First." We will use two header and two source files, though if you wanted to write this program as one single .cpp file, you could.
//first.h//A blank window#include <wx/wx.h>class Simple : public wxFrame{public: First(const wxString& title);};//first.cpp//The main file, where the window is created#include "first.h"First::First(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 150)) //change those values if you want{ Centre(); //center the window}//main.h//The header for main.cpp#include <wx/wx.h>class MyApp : public wxApp{ public: virtual bool OnInit();};//main.cpp//Displays a simple window titled "My first application"#include "main.h"#include "first.h"IMPLEMENT_APP(MyApp)bool MyApp::OnInit(){ First *first = new First(wxT("My first application")); first->Show(true); return true;}
To compile the application, run this command:
g++ main.cpp main.h first.cpp first.h `wx-config --cxxflags --libs` -o first
wx-config is a utility that helps you get the compiler and linker flags right in a seamless manner. For beginner examples like these, this sample invocation is all you need.
You now have an executable program that can become the first building block for creating GUIs with wxWidgets.
Of course a blank window won't be of any use, so let's add a button, and in the process learn how to use event handlers and communications/connections.
//button.h//Implements a quit button#include <wx/wx.h>class Button : public wxFrame{public: Button(const wxString& title); void OnQuit(wxCommandEvent & event);};//button.cpp//We create the button and define the size, text and placement.#include "button.h"Button::Button(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 150)){ wxPanel *panel = new wxPanel(this, wxID_ANY); //we create a wxPanel widget wxButton *button = new wxButton(panel, wxID_EXIT, wxT("Quit"), wxPoint(20, 20)); // place the widget inside a wxFrame widget Connect(wxID_EXIT, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(Button::OnQuit)); //connection created //the event of a button press is handled button->SetFocus(); Centre();}void Button::OnQuit(wxCommandEvent & WXUNUSED(event)){ Close(true);}//main.h//The main header#include <wx/wx.h>class MyApp : public wxApp{ public: virtual bool OnInit();};//main.cpp#include <wx/wx.h>class MyApp : public wxApp{ public: virtual bool OnInit();};
Compile this code the same way you did before, making sure that you use the correct file names, of course.
A final example serves to show how to create windows, buttons, and menus and get some use out of them. Let's start with the menu part.
//menu.h//This program will give you a file menu and a derived quit option//We include the headers and create the class#include <wx/wx.h>#include <wx/menu.h>class SimpleMenu : public wxFrame{public: SimpleMenu(const wxString& title); void OnQuit(wxCommandEvent& event); wxMenuBar *menubar; wxMenu *file;};//menu.cpp//Menu created#include "menu.h"SimpleMenu::SimpleMenu(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(280, 180)){ menubar = new wxMenuBar; file = new wxMenu; file->Append(wxID_EXIT, wxT("&Quit")); //The ampersand before a character means that it will be underlined and accesible via Alt+said chaarcter. menubar->Append(file, wxT("&File")); //So, Alt+f will give you the File menu. SetMenuBar(menubar); Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(SimpleMenu::OnQuit)); Centre();}void SimpleMenu::OnQuit(wxCommandEvent& WXUNUSED(event)){ Close(true);}//main.h//The main header#include <wx/wx.h>class MyApp : public wxApp{ public: virtual bool OnInit();};//main.cpp//Now we have it all in one place#include "main.h"#include "menu.h"IMPLEMENT_APP(MyApp)bool MyApp::OnInit(){ SimpleMenu *menu = new SimpleMenu(wxT("Simple Menu")); menu->Show(true); return true;}
The end result of this, after you compile it, is a window with a File menu that has a Quit submenu you can use to exit the application.
If you have already used C/C++ code with GTK or Qt, you will find wxWidgets a pleasure to work with, as it's a less complex way to rapidly create GUIs. If you already write GUI apps on Windows or Mac OS X, you'll like what wxWidgets has to offer. Even if you just want to begin writing graphical applications, wxWidgets, with its many supported programming languages, is a good place to start.
Allowed tags: <a> link, <b> bold, <i> italics