wxWidgets for Swing Developers

Index

  1. About
  2. How this tutorial came about
  3. Basic setup
  4. Installing wxWidgets
  5. Setting up NetBeans
  6. The main class
  7. The top frame
  8. Widgets & Sizers - Absolute Layout
  9. Widgets & Sizers - Flexible Layout
  10. Event handling - Event Tables
  11. Event handling - Connect()
  12. Resources
  13. Conclusion

About

This comparative tutorial aims to make the bridge between wxWidgets and Swing to allow for Swing developers to use their experience to learn the toolkit. Unlike other tutorials that assume some familiarity with C++ GUI toolkits, it focuses on aspects that might be tricky or unusual to developers accustomed to Swing, deliberately bypassing distracting or repetitive instructions. Once the differences are digested and the basics are grasped, wxWidgets will become familiar and you will be able to proceed on your own without problems.

How this tutorial came about

While in college, I've played with C++ driven by pure curiosity, reimplementing data-structures to learn the basics of the language. However, there was a frustrating aspect about this exploration, as the results of my efforts were mere kid-play compared to what I could do in Java at the time. Moreover, data-structures exposed me to only a narrow subset of programming problems compared to what one usually finds while developing non-trivial GUI applications. Wherever I looked for the source code of a GUI application written in C++, the code would seem alien to me. I shied away from C++ for years until about a year after my graduation, when I was invited for a C++ project that used wxWidgets as the GUI toolkit.

Having wxWidgets as my first real C++ "programming canvas" taught me that I learn much more when I'm doing something useful with what I'm learning. This reward is encouraging and leads to more exploration, which leads to more rewards, ad infinitum. wxWidgets may very well be the difference between knowing something of C++ or nothing at all for developers who would never consider learning the language without being able to create GUIs with it. If you are inexperienced in C++ and if you never considered developing a GUI application with it, wxWidgets might give the momentum you need to explore more features of the language, as well as opening your mind to the advantages of C++ when it comes to desktop applications.

Basic setup

I use the configuration below throughout this tutorial:

You may change the setup as you wish, but you will need to know what you are doing. This tutorial does not require advanced C++ skills, but if you feel you need to put yours in shape, this website is the best I know for this purpose.

Installing wxWidgets

Note: if your wxWidgets is properly installed and configured, you can skip this section.

The first thing you need to do is to make sure wxWidgets is properly installed and configured. You can easily check the status of your installation by compiling and linking the hello world found on wxWdidgets' website (the compile and link command is right at the bottom). Please don't try this on your IDE at this point because it might introduce path configuration problems. If it does not compile or link, something might be wrong with your setup. You might want to try the wx-config --cxxflags and wx-config --libs commands to see if they output anything.

I must admit I had a tough time using wxWidgets for the first time on my machine because the automated installation provided by my Ubuntu did not install it correctly. A manual installation solved everything. If you need to compile wxWidgets as I had, the instructions that come with the sources are very clear and should present no problems to get going. You should look for support on Google or support forums if you still have problems at this point.

Setting up NetBeans

In this section we will create a new C++ project on NetBeans, as well as configuring the compiler and linker flags for the program. As the C\C++ Development Pack is not bundled by default with NetBeans, you need to download and install it if you don't have it already. Once you have it installed, follow the steps below:

  1. File --> New Project... [Ctrl + Shift + F]
  2. Select C/C++ Project | C/C++ Application on the New Project dialog [screenshot]
  3. Fill in the New C/C++ Application dialog fields [screenshot]

With the project already created, the compiler and linker options need to be set-up. wxWidgets needs libraries and include directories that would be a strain to configure manually, but fortunately it comes with a small utility program that outputs all those directories and other options. You should use it to configure compiler and linker options:

wxWidgets compiler options

  1. Right click on project name on the Projects panel --> Properties
  2. On the Project Properties dialog select C/C++ --> C++ Compiler --> Command Line
  3. Add `wx-config --cxxflags` to the list of additional options

wxWidgets linker options

  1. On the Project Properties dialog select C/C++ --> Linker --> Command Line
  2. Add `wx-config --libs` to the list of additional options

Now the project is almost configured, but you still have to decide whether you will put all headers and sources in separate directories or not. If you choose the former, be sure to include the headers directory in the list of include directories (C/C++ --> C++ Compiler --> General in the Project Properties dialog). You will see a folder for source files and another for header files in the projects panel, but these don't map to any folder in your disk, so make sure you add header and source files to their appropriate directories whenever you create or add these files to your project.

The main class

You know that in C, C++ and Java every program starts in main(), however, if you take a look at the source code of many wxWidgets applications, you won't find main(). This is not an obscure C++ hack, it's just a simple indirection, after all, nothing implies that you should always create your own main(). For example: a Java desktop framework may create its own main() and call an interface implemented by you during start-up. wxWidgets has a similar approach, although it still allows you to create your own main() if you will, though this is usually not recommended because it's less portable. This section will use the recommended way, though you can see how to use your own main() if you're interested.

To create a wxWidgets application without a main(), you have to derive the wxApp class and override the OnInit() method. That's it! The listing below demonstrates how simple it is:

my_app.h


#ifndef _MY_APP_H
#define _MY_APP_H

#include <wx/app.h>

class MyApp : public wxApp {

    virtual bool OnInit();

};

#endif

my_app.cc


#include "my_app.h"

bool MyApp::OnInit() {
    return true;
}

IMPLEMENT_APP(MyApp);

You should include these on your project, and after that it should build without problems, but before you try to run it, you should be aware of the following quirks:

You may download the source code of this section.

The top frame

Now it's time to show a frame. You know that in Java you can either construct a JFrame and set its properties externally or you can derive a JFrame and set its properties internally. In wxWidgets you can also create a wxFrame both ways, with the choice depending on how you want to encapsulate the widgets contained by the frame. The listings below compare the external configuration style in wxWidgets and Swing:

External configuration of wxFrame


#include "my_app.h"

#include <wx/frame.h>

bool MyApp::OnInit() {
    wxFrame *frame = new wxFrame((wxFrame*) NULL, wxID_ANY, _T("Hello world"), wxPoint(100, 100), wxSize(320, 240));

    frame->Show(true);

    return true;
}

IMPLEMENT_APP(MyApp);

External configuration of JFrame


import javax.swing.JFrame;

public class MyApp {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Hello world");

        frame.setBounds(100, 100, 320, 240);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

}

As expected, you will see a window if you try to build and run the program. Before moving on to the internal configuration style (which will be used throughout this tutorial), I need to explain 3 parameters on wxFrame's constructor that might look peculiar from a Swing developer's perspective:


With enough explanations given for the wxFrame constructor, it's time to use the wxFrame derivation strategy that we are going to use from now on:

my_frame.h


#ifndef _MY_FRAME_H
#define _MY_FRAME_H

#include <wx/frame.h>

class MyFrame : public wxFrame {

public:

    MyFrame(const wxString &title);

};

#endif	/* _MY_FRAME_H */
	

my_frame.cc


#include "my_frame.h"

MyFrame::MyFrame(const wxString &title) : wxFrame((wxFrame*) NULL, wxID_ANY, title) {

}

If you tried the external configuration style presented on the beginning of this section, you should replace it for the code below if you are following this tutorial:

my_app.cc


#include "my_app.h"

#include "my_frame.h"

bool MyApp::OnInit() {
    MyFrame *frame = new MyFrame(_T("First frame")); 

    frame->Show(true);

    return true;
}

IMPLEMENT_APP(MyApp);
    

You may download the source code of this section.

Widgets & Sizers - Absolute Layout

Adding widgets in wxWidgets using an absolute layout is very different from Swing. The first notable difference is that you should define the parent of a component on its constructor instead of using a method like add(Component). As we will see on the next section, you will use a method that do resembles Component's add(Component) when you use a layout manager in wxWidgets, but you still have to define the parent of the component when you construct it. The second difference is that all widgets use absolute layout by default, unlike Swing where every component has its own default layout manager. The final notable difference is that if you are not going to use a layout manager (a.k.a. sizer in wxWidgets), constructing the component is enough to add it to its parent (because it is defined on the child's constructor). The code sample below illustrates this concept:

Adding two panels - Absolute layout - wxWidgets


#include <wx/panel.h>

MyFrame::MyFrame(const wxString& title) : wxFrame((wxFrame*) NULL, wxID_ANY, title) {
    new wxPanel(this, wxID_ANY, wxPoint(20, 20), wxSize(80, 120), wxSUNKEN_BORDER);
    new wxPanel(this, wxID_ANY, wxPoint(120, 20), wxSize(80, 120), wxRAISED_BORDER);
}

Adding two panels - Absolute layout - Swing (Java 6 version)


public MyFrame(String title) {
    super(title);

    JPanel panel1 = new JPanel();
    JPanel panel2 = new JPanel();

    panel1.setBounds(20, 20, 80, 120);
    panel2.setBounds(120, 20, 80, 120);

    panel1.setBorder(BorderFactory.createLoweredBevelBorder());
    panel2.setBorder(BorderFactory.createRaisedBevelBorder());

    setLayout(null);

    add(panel1);
    add(panel2);
}

Sample results - wxWidgets

First testSecond test - panels remain on their position

Fig. 1. Widgets are not resized if you use absolute layout

It is clearly visible that wxWidgets makes it very easy to configure components in absolute layouts. Note, however, that absolute layouts are rarely suitable for anything other than throw-away programs. Before we move into more flexible layouts, let's take a look at some arguments I used on the wxPanel's constructor:

You can try variations with other widgets to see how they behave and what styles are available for them. You may download the source code of this section.

Widgets & Sizers - Flexible Layout

The previous section demonstrated how to add panels into a frame using no layout manager, but for the most part you want your layout to adjust gracefully to resizing. This is when sizers (the equivalent to Swing's layout managers) come into play. This section will demonstrate this by adding two panels to a frame, where both panels have to share the space of the frame equally and maintain a fixed distance of 20 pixels from each other and from the frame's borders. Both the panels and the frame have to maintain a minimum size as well. The code samples below demonstrate this layout in Swing and wxWidgets:

Layout configuration - Two panels - Swing


public MyFrame(String title) {
    super(title);
    initOutterPanels();
}

private void initOutterPanels() {
    leftPanel = new JPanel(); 
    rightPanel = new JPanel();

    leftPanel.setBackground(Color.YELLOW);
    rightPanel.setBackground(Color.MAGENTA);

    leftPanel.setMinimumSize(new Dimension(180, 120));
    rightPanel.setMinimumSize(leftPanel.getMinimumSize());
    leftPanel.setPreferredSize(leftPanel.getMinimumSize());
    rightPanel.setPreferredSize(leftPanel.getMinimumSize());

    setMinimumSize(new Dimension(420, 160));        

    JPanel container = new JPanel();

    container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));

    container.add(leftPanel);
    container.add(Box.createHorizontalStrut(20));
    container.add(rightPanel);

    add(container, BorderLayout.CENTER);
    add(Box.createVerticalStrut(20), BorderLayout.SOUTH);
    add(Box.createVerticalStrut(20), BorderLayout.NORTH);
    add(Box.createHorizontalStrut(20), BorderLayout.WEST);
    add(Box.createHorizontalStrut(20), BorderLayout.EAST);
}

Layout configuration - Two panels - wxWidgets


#include <wx/sizer.h> // other includes are in previous examples

MyFrame::MyFrame(const wxString &title) 
        : wxFrame((wxFrame*) NULL, wxID_ANY, title),
          leftPanel(NULL), 
          rightPanel(NULL) {
          
    initOutterPanels(); // Declare this method in the header
}

void MyFrame::initOutterPanels() {
    wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);

    // Declare these panels and IDs in the header
    leftPanel = new wxPanel(this, wxID_LEFT_PANEL);
    rightPanel = new wxPanel(this, wxID_LEFT_PANEL);

    leftPanel->SetBackgroundColour(wxColour(255, 255, 0));
    rightPanel->SetBackgroundColour(wxColour(255, 0, 255));
    
    leftPanel->SetMinSize(wxSize(180, 120));
    rightPanel->SetMinSize(wxSize(180, 120));

    sizer->SetSizeHints(this);
    
    sizer->Add(leftPanel, true, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 20);
    sizer->AddSpacer(20);
    sizer->Add(rightPanel, true, wxEXPAND | wxTOP | wxBOTTOM | wxRIGHT, 20);

    SetSizer(sizer);
}

Sample results

Sizer test

Fig. 2. The minimum size of the frame is automatically calculated from the minimum size of child sizers in wxWidgets; Swing, on the other hand, requires you to guess define this size manually

As you can see, it took more lines of code to get the same result in the higher level Swing. To make things worse, in Swing I had to use another container to achieve the same result and the added struts do not use the system color. I would have to spend even more lines of code to make each strut transparent. Comparisons aside, let's briefly analyze the wxWidgets code to see how the layout specifications translate to Swing:

Now, to finish this section, let's add one button to each panel. The buttons have to maintain a minimum size while still being able to stretch horizontally. They have to keep centered on the panels and should preserve a minimum distance of 20 pixels from their parent's borders. The following code samples implement these requirements in Swing and wxWidgets:

Layout configuration - Two buttons - Swing


public MyFrame(String title) {
    super(title);
    initOutterPanels();
    initButtons();
}

private void initButtons() {
    leftButton = new JButton("Left button");
    rightButton = new JButton("Right button");

    leftButton.setMinimumSize(new Dimension(130, 30));
    rightButton.setMinimumSize(leftButton.getMinimumSize());
    leftButton.setPreferredSize(leftButton.getMinimumSize());
    rightButton.setPreferredSize(leftButton.getMinimumSize());

    GridBagLayout gridbag = new GridBagLayout();        
    GridBagConstraints c = new GridBagConstraints();

    c.weightx = 1.0;
    c.fill = GridBagConstraints.HORIZONTAL;
    c.insets = new Insets(20, 20, 20, 20);

    leftPanel.setLayout(gridbag);
    rightPanel.setLayout(gridbag);

    gridbag.setConstraints(leftButton, c);
    gridbag.setConstraints(rightButton, c);

    leftPanel.add(leftButton);
    rightPanel.add(rightButton);
}

Layout configuration - Two buttons - wxWidgets


MyFrame::MyFrame(const wxString &title) 
        : wxFrame((wxFrame*) NULL, wxID_ANY, title),
          leftPanel(NULL), rightPanel(NULL), leftButton(NULL), rightButton(NULL) {

    initPanels();
    initButtons();
}                    

void MyFrame::initButtons() {

    // Declare these buttons and IDs in the header
    leftButton = new wxButton(leftPanel, wxID_LEFT_BUTTON, _T("Left button"));
    rightButton = new wxButton(rightPanel, wxID_RIGHT_BUTTON, _T("Right button"));

    wxBoxSizer *leftSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *rightSizer = new wxBoxSizer(wxVERTICAL);

    leftButton->SetMinSize(wxSize(130, 30));
    rightButton->SetMinSize(wxSize(130, 30));

    leftSizer->AddStretchSpacer();
    leftSizer->Add(leftButton, false, wxEXPAND | wxALL, 20);
    leftSizer->AddStretchSpacer();

    rightSizer->AddStretchSpacer();
    rightSizer->Add(rightButton, false, wxEXPAND | wxALL, 20);
    rightSizer->AddStretchSpacer();

    leftSizer->SetSizeHints(leftPanel);
    rightSizer->SetSizeHints(rightPanel);

    leftPanel->SetSizer(leftSizer);
    rightPanel->SetSizer(rightSizer);
}

Sample results [wxWidgets]

Button test

Fig. 3. Centered buttons with fixed height and variable width

The code in this section may not be very useful, but it's more than enough for you to start using sizers. Note that the goal here is comprehension: once you get the idea of how the box sizer works in wxWidgets, you can do most of your layouts with simple compositions. Other methods of wxSizer are very similar to their equivalents in Swing and should pose no problems for you to understand.

You may download the documented source code of this section.

Event handling - Event Tables

If you have ever written any sizeable Java desktop program, you have probably written tons of event handling classes. A Java class may contain dozens of inner classes piled over each other to handle events of an arbitrary number of components. While this may sound familiar to you, this style of event handling is still weird to many people. It may have been strange to you while you were learning Java, but at this stage of the game this is probably a long forgotten impression. Event handling in wxWidgets is something that will bring back that awkward feeling, but as soon as it pass it will look just as natural as event handling in AWT/Swing.

wxWidgets offers more than one way to write event handling code. The most traditional one is based on event tables, which are preprocessor macros where you associate an event with a handler method. The following code samples demonstrate simple event handling in Swing and its equivalent in wxWidgets using event tables:

Event handling - Swing


public MyFrame(String title) {
    super(title);
    initOutterPanels();
    initButtons();
    initListeners();
}

private void initListeners() {
    leftButton.addActionListener(new LeftButtonListener());
    rightButton.addActionListener(new RightButtonListener());
}

private void changeParentPanelColor(ActionEvent event) {
    JButton button = (JButton) event.getSource();
    Container panel = button.getParent();
    Color color = JColorChooser.showDialog(panel, "Choose a color", panel.getBackground());

    panel.setBackground(color);
}

private void showHelloMessage(ActionEvent event) {
    JButton button = (JButton) event.getSource();
    JOptionPane.showMessageDialog(button, "Hello!", "Event test", JOptionPane.INFORMATION_MESSAGE);
}

private class LeftButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        changeParentPanelColor(event);
    }
}

private class RightButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        changeParentPanelColor(event);
        showHelloMessage(event);
    }
}

Event handling - wxWidgets - my_frame.h


class MyFrame : public wxFrame {

    // You may declare this macro anywhere in the class declaration, but you should prefer writing it at the bottom
    DECLARE_EVENT_TABLE()

};

Event handling - wxWidgets - my_frame.cc


#include <wx/colordlg.h>
#include <wx/msgdlg.h>  // other includes are in previous examples  

BEGIN_EVENT_TABLE(MyFrame, wxFrame)

    EVT_BUTTON(wxID_LEFT_BUTTON, MyFrame::changeParentPanelColor)
    EVT_BUTTON(wxID_RIGHT_BUTTON, MyFrame::changeParentPanelColor)
    EVT_BUTTON(wxID_RIGHT_BUTTON, MyFrame::showHelloMessage)

END_EVENT_TABLE()

void MyFrame::changeParentPanelColor(wxCommandEvent &event) {
    event.Skip();

    wxButton *button = static_cast<wxButton*>(event.GetEventObject());
    wxWindow *parent = button->GetParent();

    wxColour colour = wxGetColourFromUser(parent, parent->GetBackgroundColour());

    parent->SetBackgroundColour(colour);
}

void MyFrame::showHelloMessage(wxCommandEvent &event) {
    event.Skip();

    wxButton *button = static_cast<wxButton*>(event.GetEventObject());
    wxMessageBox(_T("Hello!"), _T("Event test"), wxOK | wxICON_INFORMATION, button);
} 

Sample results - Right button click

Swing and wxWidgets test results

Fig. 4. Swing and wxWidgets results, respectively. Note how both toolkits act differently with regard to centralization on the parent (the right button).

Event tables are really easy to use once you grasp the basic rules, which are detailed below:

You may have noticed that the example contains other features of wxWidgets like a color chooser panel (the equivalent to JColorChooser) and a simple dialog message (the equivalent to JOptionPane). These are explained in more detail in the wxWidgets list of convenience dialog functions.

You may download the documented source code of this section.

Event handling - Connect()

Event tables are great because they are lean and save a lot of typing — but in contrast with what? The other way to handle events: Event's Connect()/Disconnect(). You may wonder why does anyone bother using it if event tables are so advantageous. There are three basic reasons: first, event tables use macros, and that doesn't fit everyone's taste; secondly, event tables do not allow event handling to take place in some other object; finally, event tables are static and do not allow event handlers to be defined at runtime (which is default in Java). With that in mind, one could say that Connect()/Disconnect() are in fact more familiar to a Swing programmer than event tables, and they don't just look familiar, they do allow you to do everything you do with listeners in Java. In spite of all this versatility and power, it eludes me that the official wxWidgets documentation reserves little room to explain the advantages of this style of event handling, even though the authors themselves have done so. Without further ado, let's see how it works.

The following code samples demonstrate a mouse pressed event being handled in Swing and wxWidgets:

Mouse pressed event - Swing


private void initListeners() {
    leftButton.addActionListener(new LeftButtonListener()); // Declared in previous examples
    rightButton.addActionListener(new RightButtonListener()); // Declared in previous examples
    leftPanel.addMouseListener(new LeftPanelMouseListener());
}	

private void showMouseCoordinates(MouseEvent event) {
    String message = "The mouse coordinates are [" + event.getX() + ", " + event.getY() + ']';
    Component parent = (Component) event.getSource();

    JOptionPane.showMessageDialog(parent, message, "Test", JOptionPane.INFORMATION_MESSAGE);
}

private class LeftPanelMouseListener extends MouseAdapter {
    public void mousePressed(MouseEvent event) {
        showMouseCoordinates(event);
    }
}

Mouse pressed event - wxWidgets [using Connect()]


#include <sstream> // other includes are in previous examples

MyFrame::MyFrame(const wxString& title) 
        : wxFrame((wxFrame*) NULL, wxID_ANY, title),
          leftPanel(NULL), rightPanel(NULL), leftButton(NULL), rightButton(NULL) {

    initPanels(); // Declared in previous examples
    initButtons(); // Declared in previous examples
    initHandlers();
}

void MyFrame::initHandlers() {
   leftPanel->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MyFrame::showMouseCoordinates));
}

void MyFrame::showMouseCoordinates(wxMouseEvent &event) {
    event.Skip();
    wxWindow *parent = static_cast<wxWindow*>(event.GetEventObject());
    std::ostringstream oss;
    oss << "The mouse coordinates are [" << event.GetX() << ", " << event.GetY() << "]";
    wxMessageBox(_T(oss.str()), _T("Connect() test"), wxOK | wxICON_INFORMATION, parent);
}

Sample results - Left button press on left panel

connect() test

Fig. 5. Showing properties of MouseEvent and the analogous wxMouseEvent

The Connect() signature in the example deserves special attention:

if there were an exact Java equivalent of Connect() with those arguments, it would be called "addLeftButtonPressedListener()", but there's no such possibility. When you care for a single event, or not all events of the listener API, you derive an adapter like MouseAdapter, which provides void implementations of all API of the listener, allowing you to scope the events you're interested in. Contrastingly, wxWidgets allows for event handling on a per-method basis, which can be quite convenient, but it's not that automagic: the class from which this method is member must derive wxEvtHandler, and the method must follow the rules of event handler methods described in the previous section. Since MyFrame derives wxEvtHandler (indirectly), it was OK to leave aside the last two arguments of Connect(), but if you want to handle events from another class, these two last arguments must be used. For example:

Handling events from another class - MyFrame [wxWidgets]


void MyFrame::addLeftButtonHandler(wxObjectEventFunction function, wxEvtHandler *handler) const {
    leftButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, function, NULL, handler);
}               

void MyFrame::removeLeftButtonHandler(wxObjectEventFunction function, wxEvtHandler *handler) const {
    leftButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, function, NULL, handler);
}

Handling events from another class - MyApp [wxWidgets]


bool MyApp::OnInit() {
    MyFrame *frame = new MyFrame("wxWidgets test");
    
    // MyApp inherits wxEvtHandler, so I didn't have to make the class extend it
    frame->addLeftButtonHandler(wxCommandEventHandler(MyApp::onFrameLeftButtonClicked), this);
    
    frame->Show();

    return true;
}

void MyApp::onFrameLeftButtonClicked(wxCommandEvent &event) {
    event.Skip();
    wxBell();
}             
       

Handling events from another class - MyFrame [Swing]


public void addLeftButtonActionListener(ActionListener listener) {
    leftButton.addActionListener(listener);
}

public void removeLeftButtonActionListener(ActionListener listener) {
    leftButton.removeActionListener(listener);
} 

Handling events from another class - MyApp [Swing]


public static void main(String[] args) throws Exception {
    MyFrame frame = new MyFrame("Swing test");

    frame.addLeftButtonActionListener(new LeftButtonActionListener());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.setVisible(true);
}

private static class LeftButtonActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        Toolkit.getDefaultToolkit().beep();
    }
}                

Resources

Conclusion

While using Swing and wxWidgets it's difficult to refrain oneself from comparisons: Java's progress bar can be resized but wxWidgets' cannot, whereas the latter's color dialog has a color picker which the former has not, and so on. Despite the many bindings of wxWidgets, the choice of one over the other is often a choice between Java and C++, which is not always trivial. The objective of this comparative tutorial was not to provide an or, but an and to the toolkit that developers with a Java background have to solve problems. Once both toolkits are learned, the developer will have a choice and will be able to take advantage of the best that both toolkits have to offer.