views:

4283

answers:

10

What is the best way to do GUIs in Clojure?

Is there an example of some functional Swing or SWT wrapper? Or some integration with JavaFX declarative GUI description which could be easily wrapped to s-expressions using some macrology?

Any tutorials?

+10  A: 

From this page:

(import '(javax.swing JFrame JButton JOptionPane)) ;'
(import '(java.awt.event ActionListener))          ;'

(let [frame (JFrame. "Hello Swing")
     button (JButton. "Click Me")]
 (.addActionListener button
   (proxy [ActionListener] []
     (actionPerformed [evt]
       (JOptionPane/showMessageDialog  nil,
          (str "<html>Hello from <b>Clojure</b>. Button "
               (.getActionCommand evt) " clicked.")))))

 (.. frame getContentPane (add button))

 (doto frame
   (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
   .pack
   (.setVisible true)))

print("code sample");

And, of course, it would be worth looking at the interoperability section of clojure's website.

dsm
Yeah, I know you can fall back to using Swing directly, but I was askig if there is more lispy way of doing it.
Dev er dev
Also note that in the more recent versions of closure you need to add a . in front of the member function calls in the todo block.
James Dean
@James - edited the answer to reflect that
dsm
+10  A: 

If you want to do GUI programming I'd point to Temperature Converter or the ants colony.

Many things in Swing are done by sub-classing, particularly if you are creating custom components. For that there are two essential functions/macros: proxy and gen-class.

Now I understand where you are going with the more Lispy way. I don't think there's anything like that yet. I would strongly advise against trying to build a grandiose GUI-building framework a-la CLIM, but to do something more Lispy: start writing your Swing application and abstract out your common patterns with macros. When doing that you may end up with a language to write your kind of GUIs, or maybe some very generic stuff that can be shared and grow.

One thing you lose when writing the GUIs in Clojure is the use of tools like Matisse. That can be a strong pointing to write some parts in Java (the GUI) and some parts in Clojure (the logic). Which actually makes sense as in the logic you'll be able to build a language for your kind of logic using macros and I think there's more to gain there than with the GUI. Obviously, it depends on your application.

J. Pablo Fernández
Don't worry about loosing Mattisse. You can use the http://www.miglayout.com/, which is powerful enough that you can do the layouts by hand.
tomjen
You can use Matisse with Clojure, because the code generated is just Java code which can be seamlessly accessed by Clojure. There is actually a tutorial for that somewhere...
Rayne
+2  A: 

Clojure and SWT is the best approach for doing GUI(s). Essentially, SWT is a plug and play style approach for developing software.

Berlin Brown
Can you provide a link or an example? I'd be interested but have no idea of how to begin.
Carl Smotricz
Carl, second that. A good tutorial on how to write Eclipse plugins using clojure would be rather nice.
Egon Willighagen
+1  A: 

I've been developing a Java applet in which everything is written in Clojure except the applet code, which is written in Java. The applet invokes the Clojure code's callbacks of init, paint, etc from java's hooks for those methods that are defined by the applet model. So the code ends up being 99.999 percent Clojure and you don't have to think about the tiny Java piece at all for the most part.

There are some drawbacks to this approach, which I hope to discuss in more detail on the Clojure Google Group. I think the Clojure developers should include a native way of building applications. Presently you can do whatever GUI stuff you like from the REPL, but if you want a deliverable GUI application, it is necessary to write some Java to call the Clojure code. Also, it seems like the architecture of a Java Applet kind of forces you outside of Clojure's more idiomatic best practices, requiring you to use mutable state, etc.

But also, I am not very far along with Clojure yet and it might be the case that it is possible and I just haven't discovered how to do it correctly yet.

+2  A: 

There's been talk on the mailing list about a few Cells (a la Kenny Tilton's Cells) implementations. It's a pretty neat way to do GUI programming.

Joe W.
+1  A: 

Here is another very basic swing wrapping example.

; time for some swing
(import '(javax.swing JFrame JTable JScrollPane))
(import '(javax.swing.table DefaultTableModel))

(let 
  [frame (JFrame. "Hello Swing")
    dm (DefaultTableModel.)
      table (JTable. dm)
     scroll (JScrollPane. table)]
  (doto dm
      (.setNumRows 30)
     (.setColumnCount 5))
  (.. frame getContentPane (add scroll))
    (doto frame
      (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) 
     (.pack)
     (.setVisible true)))
James Dean
+1  A: 

I don't think there is an official one, but personally I would take advantage of the fact that I am using one of the most powerful language in the world and just imagine what the perfect gui code would look like:

(form {:title :on-close dispose :x-size 500 :y-size 450}
  [(button {:text "Close" :id 5 :on-click #(System/exit 0) :align :bottom})
   (text-field {:text "" :on-change #(.println System/out (:value %)) :align :center})
   (combo-box {:text "Chose background colour" :on-change background-update-function
               :items valid-colours})])

Your idea would differ but this should hopefully the above gives you some idea.

tomjen
Looks like groovy SwingBuilder dsl translated to Clojure.
Dev er dev
@dev-er-devThat is very possible, I have never used groovy, but great minds do thing alike :)
tomjen
@tomjen: "Thing alike"?
Ralph
+3  A: 

There is a wrapper for MigLayout in clojure contrib. You can also take a look http://gist.github.com/261140. I am basically putting up whatever code I am writing as I am learning swing/miglayout.

dsm's example re-written in a lispy way using contrib.swing-utils

(ns test
      (:import (javax.swing JButton JFrame))
      (:use (clojure.contrib
          [swing-utils :only (add-action-listener)])))

    (defn handler
      [event]
      (JOptionPane/showMessageDialog nil,
        (str "<html>Hello from <b>Clojure</b>. Button "
          (.getActionCommand event) " clicked.")))

    (let [ frame (JFrame. "Hello Swing") 
           button (JButton. "Click Me")  ]
      (add-action-listener button handler)
        (doto frame
          (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
          (.add button)
          (.pack)
          (.setVisible true)))
Abhijith
A: 

I know that you are hinting for classical desktop solutions, but web fits quite well with clojure. I've written a complete audio application where everything is hooked up so that if you add music to the audio folder it is reflected in the web UI. Just saying that Desktop application isn't the only way :)

Anders Rune Jensen
+7  A: 

Stuart Sierra recently published a series of blog posts on GUI-development with clojure (and swing). Start off here: http://stuartsierra.com/2010/01/02/first-steps-with-clojure-swing

steglig