6. Threading Issues

It is important that only one thread calls the GUI functions. The main rule of thumb is that only the main event thread should call any GUI functions and interact with GUI objects. There are multiple techniques to handle threads.

The lowest level technique is to create custom events and use wxPostEvent(). wxPostEvent() is thread safe and is callable outside the main event thread. The event handler will run within the event thread.

wx4j provides two methods on the wxJUtil class: invokeLater() and invokeAndWait(). Swing programmers will be very at home with these two methods as they are functionally identical to the same methods on SwingUtilities. These methods let you specify that some code be executed in the event thread.

Finally, you may use the wxJWorker class to provide an even higher level abtraction. This is also functionally identical to the SwingWorker class.

6.1. Using the wxJworker Class

To use the wxJWorker class, you must subclass it and override construct(). Put the time consuming code in construct(). To use your wxJWorker subclass, instantiate it and then call start(). start() starts the thread and calls your construct(). For example:

public void handleEvent(wxCommandEvent event)
{
    final wxJWorker worker = new wxJWorker()
    {
        public Object construct()
        {
            // ... code that may  take a while to execute ...
            return someValue;
        }
    });
}

The value that construct() returns may be any object. To get the value, you may call get(), but be careful as get() blocks until a value is returned. While you may use get() to detect when the time consuming code finishes, it is better to override finished() in your wxJWorker subclass. finished() also runs in the event thread so you can update any GUI objects.

The following example is slightly modified from the wxJWorker demo. See the demo source code for the full code.

Object doWork()
{
    try
    {
        for (int i = 0; i <= NUMLOOPS; i++)
        {
            updateStatus(i);
            if (Thread.interrupted())
            {
                throw new InterruptedException();
            }
            Thread.sleep(100);
        }
    }
    catch (InterruptedException e)
    {
        updateStatus(0);
        return "Interrupted";  // wxJWorker.get() returns this
    }
    return "All Done";         // or this
}

class OnStart implements wxCommandListener
{
    public void handleEvent(wxCommandEvent event)
    {
        mStartButton.Disable();
        mInterruptButton.Enable();
        mStatusField.SetLabel("Working...");

        mWorker = new wxJWorker()
        {
            public Object construct()
            {
                return doWork();
            }

            public void finished()
            {
                mStartButton.Enable();
                mInterruptButton.Disable();
                mStatusField.SetLabel(get().toString());
            }
        };
        mWorker.start();
    }
}

6.2. Using the invokeLater Method

You can use invokeLater() to run code in the event dispatching. It takes a Runnable object and will invoke run() in the event thread. invokeLater() returns immediately and does not wait for the code to be executed. Here's an example to set the text of a status bar in a frame:

Runnable updateStatus = new Runnable()
{
    public void run()
    {
        someFrame.SetStatusText("Updated status");
    }
};
wxJUtil.invokeLater(updateStatus);

6.3. Using the invokeAndWait Method

invokeAndWait() is similar to invokeLater(), except it does not return until run() finishes. This may be used to display a dialog outside the event thread and wait for it to finish:

public void showDialog() throws Exception
{
     Runnable showDialog = new Runnable()
     {
         public void run()
         {
             wxMessageBox("Hello there", "Hello", wxYES | wxICON_INFORMATION,
                          mainFrame);
         }
     };
     wxJUtil.invokeAndWait(showDialog);
}

See Example2.java of the wxJWorker demo for a complete set of working code.