Chapter 2 Getting Started

In this chapter, we’ll get a feel for the structure of a simple wxWidgets program, using a tiny sample. We’ll look at where and how a wxWidgets application starts and ends, how to show the main window, and how to react to commands from the user. Following the wxWidgets philosophy of keeping things nice and simple, that’s all we’re going to cover in this chapter. You may also want to refer to Appendix A, “Installing wxWidgets.”

A Small wxWidgets Sample

Figure 2-1 shows what our sample looks like under Windows.

Figure 2-1 Minimal sample under Windows

Minimal sample under Windows

The minimal wxWidgets application shows a main window (a wxFrame) with a menu bar and status bar. The menus allow you to show an “about box” or quit the program. Not exactly a killer app, but it’s enough to show some of the basic principles of wxWidgets—and to reassure you that you can start simple and work your way up to a complete application as your confidence and expertise grow.

The Application Class

Every wxWidgets application defines an application class deriving from wxApp. There is only one instance of it, and this instance represents the running application. At the very least, your class should define an OnInit function that will be called when wxWidgets is ready to start running your code (equivalent to main or WinMain when writing a C or Win32 application).

Here is the smallest application class declaration you can sensibly write:

// Declare the application class
class MyApp : public wxApp
{
public:
    // Called on application startup
    virtual bool OnInit();
};

The implementation of OnInit usually creates at least one window, interprets any command-line arguments, sets up data for the application, and performs any other initialization tasks required for the application. If the function returns true, wxWidgets starts the event loop that processes user input and runs event handlers as necessary. If the function returns false, wxWidgets will clean up its internal structures, and the application will terminate.

A simple implementation of OnInit might look like this:

bool MyApp::OnInit()
{
    // Create the main application window
    MyFrame *frame = new MyFrame(wxT("Minimal wxWidgets App"));

    // Show it
    frame->Show(true);

    // Start the event loop
    return true;
}

This creates an instance of our new class MyFrame (we’ll define this class shortly), shows it, and returns true to start the event loop. Unlike child windows, top-level windows such as frames and dialogs need to be shown explicitly after creation.

The frame title is passed to the constructor wrapped in the wxT() macro. You’ll see this used a lot in wxWidgets samples and in the library code itself—it converts string and character literals to the appropriate type to allow the application to be compiled in Unicode mode. This macro is also known by the alias _T(). There is no run-time performance penalty for using it. (You’ll also see the underscore macro _() used to enclose strings, which tells wxWidgets to translate the string. See Chapter 16, “Writing International Applications,” for more details.)

Where is the code that creates the instance of MyApp? wxWidgets does this internally, but you still need to tell wxWidgets what kind of object to create. So you need to add a macro in your implementation file:

// Give wxWidgets the means to create a MyApp object
IMPLEMENT_APP(MyApp)

Without specifying the class, wxWidgets would not know how to create a new application object. This macro also inserts code that checks that the application and library were compiled using the same build configuration, allowing wxWidgets to report accidental mismatches that might later cause a hard-to-debug run-time failure.

When wxWidgets creates a MyApp object, it assigns the result to the global variable wxTheApp. You can use this in your application, but it would be more convenient if you didn’t have to cast the wxApp pointer to MyApp. By inserting this macro after your application class declaration:

// Implements MyApp& wxGetApp()
DECLARE_APP(MyApp)

you can then call the function wxGetApp, which returns a reference to the MyApp object.

The Frame Class

Let’s look at the frame class MyFrame. A frame is a top-level window that contains other windows, and usually has a title bar and menu bar. Here’s our simple frame class declaration that we will put after the declaration of MyApp:

// Declare our main frame class
class MyFrame : public wxFrame
{
public:
    // Constructor
    MyFrame(const wxString& title);

    // Event handlers

    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);

private:
    // This class handles events
    DECLARE_EVENT_TABLE()
};

Our frame class has a constructor, two event handlers to link menu commands to C++ code, and a macro to tell wxWidgets that this class handles events.

The Event Handlers

As you may have noticed, the event handler functions in MyFrame are not virtual and should not be virtual. How, then, are they called? The answer lies in the event table, as follows.

// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
    EVT_MENU(wxID_EXIT,  MyFrame::OnQuit)
END_EVENT_TABLE()

An event table, placed in a class’s implementation file, tells wxWidgets how events coming from the user or from other sources are routed to member functions.

With the event table shown previously, mouse clicks on menu items with the identifiers wxID_EXIT and wxID_ABOUT are routed to the functions MyFrame::OnQuit and MyFrame::OnAbout, respectively. EVT_MENU is just one of many event table macros you can use to tell wxWidgets what kind of event should be routed to what function. The identifiers used here are predefined by wxWidgets, but you will often define your own identifiers, using enums, consts, or preprocessor defines.

This kind of event table is a static way of routing events, and cannot be changed at runtime. In the next chapter, we’ll describe how to set up dynamic event handlers.

While we’re dealing with event tables, let’s see the two functions we’re using as event handlers.

void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxString msg;
    msg.Printf(wxT("Hello and welcome to %s"),
               wxVERSION_STRING);

    wxMessageBox(msg, wxT("About Minimal"),
                 wxOK | wxICON_INFORMATION, this);
}

void MyFrame::OnQuit(wxCommandEvent& event)
{
    // Destroy the frame
    Close();
}

MyFrame::OnAbout shows a message box when the user clicks on the About menu item. wxMessageBox takes a message, a caption, a combination of styles, and a parent window.

MyFrame::OnQuit is called when the user clicks on the Quit menu item, thanks to the event table. It calls Close to destroy the frame, triggering the shutdown of the application, because there are no other frames. In fact, Close doesn’t directly destroy the frame—it generates a wxEVT_CLOSE_WINDOW event, and the default handler for this event destroys the frame using wxWindow::Destroy.

There’s another way the frame can be closed and the application shut down—the user can click on the close button on the frame, or select Close from the system (or window manager) menu. How does OnQuit get called in this case? Well, it doesn’t—instead, wxWidgets sends a wxEVT_CLOSE_WINDOW event to the frame via Close (as used in OnQuit). wxWidgets handles this event by default and destroys the window. Your application can override this behavior and provide its own event handler—for example, if you want to ask the user for confirmation before closing. For more details, please see Chapter 4, “Window Basics.”

This sample doesn’t need it, but most applications should provide an OnExit function in its application class to clean up data structures before quitting. Note that this function is only called if OnInit returns true.

The Frame Constructor

Finally, we have the frame constructor, which implements the frame icon, a menu bar, and a status bar.

#include "mondrian.xpm"

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
    // Set the frame icon
    SetIcon(wxIcon(mondrian_xpm));

    // Create a menu bar
    wxMenu *fileMenu = new wxMenu;

    // The "About" item should be in the help menu
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(wxID_ABOUT, wxT("&About... F1"),
                     wxT("Show about dialog"));

    fileMenu->Append(wxID_EXIT, wxT("E&xit Alt-X"),
                     wxT("Quit this program"));

    // Now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, wxT("&File"));
    menuBar->Append(helpMenu, wxT("&Help"));

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);

    // Create a status bar just for fun
    CreateStatusBar(2);
    SetStatusText(wxT("Welcome to wxWidgets!"));
}

This constructor calls the base constructor with the parent window (none, hence NULL), window identifier, and title. The identifier argument is wxID_ANY, which tells wxWidgets to generate an identifier itself. The base constructor creates the actual window associated with the C++ instance—another way to achieve this is to call the default constructor of the base class, and then explicitly call wxFrame::Create from within the MyFrame constructor.

Small bitmaps and icons can be implemented using the XPM format on all platforms. XPM files have valid C++ syntax and so can be included as shown previously; the SetIcon line creates an icon on the stack using the C++ variable mondrian_xpm defined in mondrian.xpm, and associates it with the frame.

The menu bar is created next. Menu items are added using the identifier (such as the standard identifier wxID_ABOUT), the label to be displayed, and a help string to be shown on the status bar. Within each label, a mnemonic letter is marked by a preceding ampersand, and an accelerator is preceded by the tab character ( ). A mnemonic is the letter a user presses to highlight a particular item when the menu is displayed. An accelerator is a key combination (such as Alt+X) that can be used to perform that action without showing the menu at all.

The last thing that the constructor does is to create a status bar with two fields at the bottom of the frame and set the first field to the string “Welcome to wxWidgets!”

The Whole Program

It’s worth putting together the bits so you can see what the whole program looks like. Normally, you’d have a separate header file and implementation file, but for such a simple program, we can put it all in the same file.

Listing 2-1 The Complete Example

// Name:        minimal.cpp
// Purpose:     Minimal wxWidgets sample
// Author:      Julian Smart

#include "wx/wx.h"


// Declare the application class
class MyApp : public wxApp
{
public:
    // Called on application startup
    virtual bool OnInit();
};

// Declare our main frame class
class MyFrame : public wxFrame
{
public:
    // Constructor
    MyFrame(const wxString& title);

    // Event handlers
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);

private:
    // This class handles events
    DECLARE_EVENT_TABLE()
};

// Implements MyApp& GetApp()
DECLARE_APP(MyApp)

// Give wxWidgets the means to create a MyApp object
IMPLEMENT_APP(MyApp)

// Initialize the application
bool MyApp::OnInit()
{
    // Create the main application window
    MyFrame *frame = new MyFrame(wxT("Minimal wxWidgets App"));

    // Show it
    frame->Show(true);

    // Start the event loop
    return true;
}

// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
    EVT_MENU(wxID_EXIT,  MyFrame::OnQuit)
END_EVENT_TABLE()

void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxString msg;
    msg.Printf(wxT("Hello and welcome to %s"),
               wxVERSION_STRING);

    wxMessageBox(msg, wxT("About Minimal"),
                 wxOK | wxICON_INFORMATION, this);
}

void MyFrame::OnQuit(wxCommandEvent& event)
{
    // Destroy the frame
    Close();
}

#include "mondrian.xpm"

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
    // Set the frame icon
    SetIcon(wxIcon(mondrian_xpm));

    // Create a menu bar
    wxMenu *fileMenu = new wxMenu;

    // The "About" item should be in the help menu
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(wxID_ABOUT, wxT("&About... F1"),
                     wxT("Show about dialog"));

    fileMenu->Append(wxID_EXIT, wxT("E&xit Alt-X"),
                     wxT("Quit this program"));

    // Now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, wxT("&File"));
    menuBar->Append(helpMenu, wxT("&Help"));

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);

    // Create a status bar just for fun
    CreateStatusBar(2);
    SetStatusText(wxT("Welcome to wxWidgets!"));
}

Compiling and Running the Program

The sample can be found on the accompanying CD-ROM in examples/chap02, which you should copy to a folder on your hard drive for compiling. Because it’s not possible to provide makefiles that work “out of the box” with every reader’s software environment, we provide a DialogBlocks project file with configurations for most platforms and compilers. See Appendix C, “Creating Applications with DialogBlocks,” for help with configuring DialogBlocks for your compiler. We also cover compiling wxWidgets applications in detail in Appendix B, “Building Your Own wxWidgets Applications.”

Install wxWidgets and DialogBlocks from the accompanying CD-ROM. On Windows, you should install one or more of the compilers provided on the CD-ROM if you do not already own a suitable compiler. After setting your wxWidgets and compiler paths in the DialogBlocks Paths settings page, open the file examples/chap02/minimal.pjd. Select a suitable configuration for your compiler and platform such as MinGW Debug or VC++ Debug (Windows), GCC Debug GTK+ (Linux), or GCC Debug Mac (Mac OS X), and press the green Build and Run Project button. You may be prompted to build wxWidgets if you have not already built it for the selected configuration.

You can also find a similar sample in samples/minimal in your wxWidgets distribution. If you do not wish to use DialogBlocks, you can simply compile this sample instead. See Appendix A, “Installing wxWidgets,” for instructions on how to build wxWidgets samples.

Program Flow

This is how the application starts running:

1. Depending on platform, the main, WinMain, or equivalent function runs (supplied by wxWidgets, not the application). wxWidgets initializes its internal data structures and creates an instance of MyApp.

2. wxWidgets calls MyApp::OnInit, which creates an instance of MyFrame.

3. The MyFrame constructor creates the window via the wxFrame constructor and adds an icon, menu bar, and status bar.

4. MyApp::OnInit shows the frame and returns true.

5. wxWidgets starts the event loop, waiting for events and dispatching them to the appropriate handlers.

As noted here, the application terminates when the frame is closed, when the user either selects the Quit menu item or closes the frame via standard buttons or menus (these will differ from one platform to the next).

Summary

This chapter gave you an idea of how a really simple wxWidgets application works. We’ve touched on the wxFrame class, event handling, application initialization, and creating a menu bar and status bar. However complicated your own code gets, the basic principles of starting the application will remain the same, as we’ve shown in this small example. In the next chapter, we’ll take a closer look at events and how your application handles them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.79.206