Tuesday, December 21, 2010

Clojure Launcher pt. 2; now with ActionListeners!

I finally got a chance to work some more on the Clojure launcher GUI program.  I refactored a lot of the code and decided to make use of some closures.  When I started looking at my code, it actually seemed like a macro might be more useful, and I'll explain why I think so in a little bit.

But here so far is my new code.

   1 (ns sojourner.gui
   2   (:import (javax.swing JPanel JButton JLabel JFrame JTextField JFileChooser)
   3            (java.awt.event ActionListener)
   4            (net.miginfocom.swing MigLayout)))
   5 
   6 (def jpanel (JPanel. (MigLayout.)))
   7 
   8 ; Create a file chooser that will pop-up if the user clicks
   9 ; on any of the Browse buttons
  10 (def fc (JFileChooser.))
  11 
  12 ;; This is the function that will be called when any of the Browse buttons are clicked
  13 ;; Basically, we open up a JFileChooser dialog, and we capture the file/directory
  14 ;; that the user selects.  We then append this to the JTextField
  15 (defn get-file-selection [ ]
  16     (let [ fc (JFileChooser.) 
  17            retval (.showOpenDialog fc nil) ]
  18        (if (= retval JFileChooser/APPROVE_OPTION)
  19           (do 
  20              (println (.getSelectedFile fc))
  21              (.getSelectedFile fc))
  22            "")))
  23 
  24 ; Create a proxy for clicking on the Browse button
  25 (def on-click (proxy [ActionListener] []
  26                 (actionPerformed [ event ] (get-file-selection))))
  27                     
  28 
  29 (defn make-row-fn 
  30     [ panel lbl-string fld-string btn-string ]
  31     (fn [ panel ]
  32       (let [btn (JButton. btn-string) ]
  33          (.addActionListener btn on-click)
  34          (doto panel
  35            (.add (JLabel. lbl-string))
  36            (.add (JTextField. fld-string 10))
  37            (.add btn "wrap" ) ) ) ) )
  38 
  39 ;; It seems to me that all these make-row functions could be encapsulated
  40 ;; inside of a macro, or at the least, return a function which does the following
  41 (def make-ext-jar-row (make-row-fn jpanel "External Jars" "" "Browse"))
  42 (def make-classpath-row (make-row-fn jpanel "Class path" "" "Browse"))
  43 (def make-clojars-row (make-row-fn jpanel "Clojure files" "" "Browse"))
  44 
  45 
  46 (defn make-launcher [ panel ]
  47    ( let [p (doto panel
  48              (make-ext-jar-row )
  49              (make-classpath-row )
  50              (make-clojars-row )) ]
  51      ; return the frame after we're done here
  52      (doto (JFrame. "Java Launcher")
  53        (.setContentPane p)
  54        (.setSize 300 150)
  55        (.setVisible true))))
  56 
  57 (def frame (make-launcher jpanel))
  58 
  59  
 
 And this is what it looks like


Yeah I know, it's not a lot to look at, but now if you click the Browse button, a JFileChooser dialog will appear. However, there's still a lot to do:

1. Get the file selected, and enter it in the corresponding JTextField
2. Rework the make-row-fn as a macro, so that each button can have a different proxy
3. I'm going to rework this to use leiningen (clojure's version of maven)
4. A new JTextArea which will contain either the repl launched or the running program
5. Some fields to enter the jar or main to run (eg java -jar myjar.jar)

 

No comments:

Post a Comment