(See my full list of Clojure Swing examples and tutorials at Clojure Swing Interop)
When working with UI elements in Clojure Swing, your “go to” event handler is the ActionListener found in the java.awt.event package. This is a one-size-fits-all handler that works for many general situations where you just need to know **something** happened.
The fist hurdle to overcome is what Clojure technique should you use to implement the ActionListener interface? The correct answer is reify .
Reify gives you an anonymous implementation of an interface. It is perfect for implementing Java event interfaces that are rarely named once created. Reify takes the interface name followed by method implementations as it’s arguments. The one trick that may throw off seasoned Java programmers implementing methods in Clojure’s reify, is that the first argument to functions used to implement methods is always an explicit this . this is usually hidden in Java implementations of methods. It’s there, just not visible.
For example, here is reify implementing an ActionListener for a typical JButton called my-button .
1 2 3 |
(.addActionListener my-button (reify ActionListener (actionPerformed [this e] (println "Clicked")))) |
Here’s an example of a JFrame containing a JButton that prints “Clicked” to the console when clicked.
Here is the full source code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
(ns swingproject.core (:gen-class) (:import [javax.swing SwingUtilities JFrame JButton] [java.awt FlowLayout] [java.awt.event ActionListener])) (defn create-and-show-gui [] (let [my-frame (doto (JFrame. "My Frame") (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) (.setLocationRelativeTo nil)) my-button (JButton. "Click ME!") content-pane (doto (.getContentPane my-frame) (.setLayout (FlowLayout.)))] (.addActionListener my-button (reify ActionListener (actionPerformed [this e] (println "Clicked")))) (.add content-pane my-button) (.pack my-frame) (.setSize my-frame 300 200) (.setVisible my-frame true))) (defn -main "entry point for app" [& args] (SwingUtilities/invokeLater create-and-show-gui)) |