(See my full list of Clojure Swing examples and tutorials at Clojure Swing Interop)
When developing Swing GUIs for Clojure, understanding and using SwingUtilities/invokeLater is crucial.
Event Dispatch Thread
Don’t confuse “thread” in this case with Clojure threading macros such as -> and --> . Threading here refers to concurrency.
Swing GUI components are not safe to access concurrently. If two threads modify the same Swing component at the same time, the result is unpredictable. Java solved this problem by introducing the event dispatch thread. All modification Swing displays and component values should happen on the event dispatch thread.
There is only one event dispatch thread. You access it by creating a Java Runnable and passing it to SwingUtilities/invokeLater . Lucky for us, all Clojure functions are Java Runnables. Here’s the general format.
1 2 3 4 5 6 |
(defn my-gui-modifier [] ;; Do some Swing changes here ) (defn modit [] (SwingUtilities/invokeLater my-gui-modifier)) |
Warning
Remember, ALL the screen rendering and modifications to your Swing components happen on the event dispatch thread. That means, if you tie up the event dispatch thread doing something time consuming, your app will appear to hang. This creates a horrible user experience. Any runnables you create should complete quickly.
On a somewhat related note, any time a Swing component alerts you to an event or a value change, you will want to hand back that thread immediately and use a new thread to do any long tasks associated with the notifications.