(See my full list of Clojure Swing examples and tutorials at Clojure Swing Interop)
Here is a full app demonstrating use of Swing from Clojure. Toy apps usually gloss over import code. For example, real Swing requires proper use of the event thread, and combining multiple layout types to get more complex behavior.
Here’s the full source.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
(ns swingproject.core (:gen-class) (:import [javax.swing SwingUtilities JFrame JTextField JPanel JLabel] [java.awt FlowLayout] [java.awt.event ActionListener])) (defn convert-temp [celsius fahrenheit to-celsius] (if to-celsius (let [f (.getText fahrenheit) f-as-int (Integer/parseInt f) c (* 5/9 (- f-as-int 32))] (SwingUtilities/invokeLater #(.setText celsius (str (float c))))) (let [c (.getText celsius) c-as-int (Integer/parseInt c) f (+ 32 (* 9/5 c-as-int))] (SwingUtilities/invokeLater #(.setText fahrenheit (str (float f))))))) (defn create-and-show-gui [] (let [my-frame (doto (JFrame. "My Frame") (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) (.setLocationRelativeTo nil)) celsius-panel (JPanel. (FlowLayout.)) fahrenheit-panel (JPanel. (FlowLayout.)) celsius (JTextField. "0" 10) fahrenheit (JTextField. "32" 10) content-pane (doto (.getContentPane my-frame) (.setLayout (FlowLayout.)))] (.addActionListener celsius (reify ActionListener (actionPerformed [this e] (convert-temp celsius fahrenheit false)))) (.addActionListener fahrenheit (reify ActionListener (actionPerformed [this e] (convert-temp celsius fahrenheit true)))) (.add celsius-panel (JLabel. "Celsius")) (.add celsius-panel celsius) (.add fahrenheit-panel (JLabel. "Fahrenheit")) (.add fahrenheit-panel fahrenheit) (.add content-pane celsius-panel) (.add content-pane fahrenheit-panel) (.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)) |
Note that #(<some UI code>) is used to pass in a function to the event dispatch thread, otherwise you have null pointer exceptions due to the code being executed BEFORE it is passed to the event dispatch thread.