3. Handling Events

Probably the biggest difference between wx4j and wxWidgets is how events are handled. In C++, you connect an event to a specific method to handle the event. This is not possible in Java since there is no concept of pointers to member functions. It would be possible to use reflection to try and mimic pointers to member functions, but the syntax would be very verbose, and it would not be type safe. Thus, interfaces are used as event handlers, which is more natural to Java and allows the use of Java features such as inner classes.

3.1. Listener Interfaces

For every event class, there is a corresponding interface used for handling events of that type, called a listener interface. All interfaces contain a handleEvent() method with the corresponding event being passed in. For example, the interface used to handle a wxCommandEvent looks like:

/**
 * Listener interface for receiving command events.
 */
public interface wxCommandListener
{
    /**
     * Invoked when a command event occurs.
     *
     * @param event Command event
     */
    public void handleEvent(wxCommandEvent event);
}

Therefore, to handle an event, a class must implement this interface:

public class CommandEventHandler implements wxCommandListener
{
    public void handleEvent(wxCommandEvent event)
    {
        // ... handle command event ...
    }
}

The general naming convetion for listener interfaces is to take the name of the event class, and replace Event with Listener. The only current exception to the rule is wxJEvent, which has the interface name of wxJEventInterface.

3.2. Connecting Events

In C++ there are macros to connect a method to an event by creating static event tables. In Java there are no macros, so methods are used to do the connection. These connections are also done at run time rather than compile time, usually in a constructor. The Java method names correspond exactly their C++ macro counterparts. For example, to connect a button up to the previous command event handler, the following code snippet would work:

wxCommandListener eventHandler = new CommandEventHandler();
wxButton button = new wxButton(parent, -1, "Press Me");
EVT_BUTTON(button.GetId(), eventHandler);

The observant reader will have noticed that EVT_BUTTON() is called as if it were a method on the current class. The truth of the matter is that the macro equivalent methods are defined off the wxEvtHandler class. Any class inheriting from this may call the "macros" without scoping. There are, however, cases, when you want to invoke these methods on some other object than this. In these cases, simply invoke the EVT_* methods like any other method:

wxListBox box = new wxListBox(this, -1);
// You can connect up a handler to this directly
EVT_LISTBOX(box.GetId(), listboxSelectedHandler);

// However, to intercept the right mouse button on the box only, you
// must scope the connecting method
box1.EVT_RIGHT_UP(rightUpHandler);

3.3. Event Handling Techniques

Since event handlers just need to implement listener interfaces, there are serveral techniques for event handlers. The first and most obvious, is to use a full blown public class, like CommandEventHandler above. To use an anonyous inner class instead, the above code would change to:

wxButton button = new wxButton(parent, -1, "Press Me");
EVT_BUTTON(button.GetId(), new wxCommandListener()
{
    public void handleEvent(wxCommandEvent event)
    {
        // ... handle event using an anonymous inner class ...
    }
});

My personal favorite is to use a named inner class:

public class MyPanel extends wxPanel
{
    public MyPanel(wxWindow parent)
    {
        super(parent, -1);
        wxButton button = new wxButton(parent, -1, "Press Me");
        EVT_BUTTON(button.GetId(), new OnButtonPress());
    }

    class OnButtonPresss implements wxCommandListener
    {
        public void handleEvent(wxCommandEvent event)
        {
            // ... handle event ...
        }
    }
}

Or use an externally defined anonymous inner class:

public class MyPanel extends wxPanel
{
    public MyPanel(wxWindow parent)
    {
        super(parent, -1);
        wxButton button = new wxButton(parent, -1, "Press Me");
        EVT_BUTTON(button.GetId(), onButtonPress);
    }

    private wxCommandListener onButtonPress = new wxCommandListener()
    {
        public void handleEvent(wxCommandEvent event)
        {
            // ... handle event ...
        }
    };
}

One noteworthy point is that within inner classes, to use the "outer" this, you must scope it, since this refers to the inner class itself:

public class MyFrame extends wxFrame
{
    class OnButtonPresss implements wxCommandListener
    {
        public void handleEvent(wxCommandEvent event)
        {
            // Last argument requires a wxWindow, so use the outer
            // frame
            wxMessageBox("Message", "Title", wxOK | wxICON_INFORMATION,
                         MyFrame.this);
        }
    }
}

3.4. Custom Events

The wxJEvent class allows custom events to be used from Java code. The event ID is set in the constructor and it can hold any Java cloneable object. The object must be cloneable because wxPostEvent() clones the event for thread safety. The event handler must implement wxJEventListener and connected using EVT_JCUSTOM(). An example using a custom event is:

public class MyPanel extends wxPanel
{
    public static final int CUSTOM_EVENT_ID = wxNewEventType();

    public MyPanel(/* ... */)
    {
        EVT_JCUSTOM(CUSTOM_EVENT_ID, new OnCustomEvent());
    }
    
    public void fireCustomEvent()
    {
        wxJEvent event = new wxJEvent(CUSTOM_EVENT_ID);
        event.SetData("String data");
        wxPostEvent(this, event);
    }

    class OnCustomEvent implements wxJEventListener
    {
        public void handleEvent(wxJEvent event)
        {
            String data = (String) event.GetData();
            System.out.println("Got custom data: " + data);
        }
    }
}

The wxJCommandEvent is similar, but broken at the moment...