The ease of gui's.
So clj-swing gets more and more interesting. There are some nice new features like text boxes that are directly cupeled to the content with a ref of a string. So I want to take this as an opportunity to show off a little. As a example I picked the Temperature converter from Stuart Sierras blog . Why? Since it is simple and since it allows a nice comparison of ‘plain’ swing coding and clj-swing coding.
Lets start with the basics. First we need some helper functions.
Converting the temperatures forth and back, This is more then less directly taken from Stuarts blog.
(defn c-to-f [c]
(+ (* c 9/5) 32))
(defn f-to-c [f]
(* (- f 32) 5/9))And some helper that we will need later to make it easily to update the text boxes. We use constantly to return a function so we can just alter the ref with this.
(defn convert-temp [converter temp]
(constantly (str (Math/round (float (converter (Double/parseDouble (.trim temp))))))))Now it gets interesting, first we need to set up two refs for the content of the text box. Since we need them nowhere else we put this in a let.
(defn converter-example []
(let [c (ref "")
f (ref "")]Now c and f will hold the string for Celsius and Fahrenheit. We initialize them with empty strings. Next up is creating the gui itself, we start with a frame form, this takes some arguments. You see :layout :grid-bag here, this is a short form of :layout (GridBagLayout.) :constrains (GridBagConstrains.). Also since we want to pack the frame and show it right after the call we add :show true and :pack true.
(frame :layout :grid-bag :show true :pack truefNow we go to set up the layout, this look a lot like Stuart’s code since I adopted his idea. The setup is somewhat like a let with added support for constrains.
[:gridx 0 :gridy 0 :anchor :LINE_END
_ (label "C")
:gridy 1
_ (label "F")
:gridx 1 :anchor :LINE_STARTThe two labels are pretty boring and straight forward, you pass it a string and it makes a label. Now here comes the interesting part, the text fields. Lets first summarize what we want. The user types a temperature in the field and presses return, the change gets validated and the other field updated. Now lets see how we do this:
_ (text-field :str-ref f :columns 10
:action ([_]
(if (re-find #"^\d+$" @f)
(dosync (alter c (convert-temp f-to-c @f))))))Lets take the arguments apart, :columns 10 This tells the text field that it should be 10 chars wide. Now the interesting part: :str-ref f tells the text field to keep up to date with the ref of f we defined earlier in the let. This means if the text field changes f changes and if f changes the text field changes.
Now to :action, this is a function that gets called when the ‘action’ happens, in the case of a text field this means when return is pressed. It takes one parameter, the event, we don’t care about this right now so we just ignore it. Then we use a regexp to see if the content is a number and if it is we just alter c with convert-temp. Done, the updating in the GUI happens neat isn’t it.
So here to finish up the rest of the code just to finish it up:
:gridy 0
_ (text-field :str-ref c :columns 10
:action ([_]
(if (re-find #"^\d+$" @c)
(dosync (alter f (convert-temp c-to-f @c))))))])))Here we go and that is how it looks:

Trackbacks
Use the following link to trackback from your own site:
http://blog.licenser.net/trackbacks?article_id=68
