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?
I will humbly suggest Seesaw.
Here's a REPL-based tutorial that assumes no Java or Swing knowledge.
Seesaw's a lot like what #tomjen suggests. Here's "Hello, World":
(use 'seesaw.core)
(-> (frame :title "Hello"
:content "Hello, Seesaw"
:on-close :exit)
pack!
show!)
and here's #Abhijith and #dsm's example, translated pretty literally:
(ns seesaw-test.core
(:use seesaw.core))
(defn handler
[event]
(alert event
(str "<html>Hello from <b>Clojure</b>. Button "
(.getActionCommand event) " clicked.")))
(-> (frame :title "Hello Swing" :on-close :exit
:content (button :text "Click Me" :listen [:action handler]))
pack!
show!)
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
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.
Nobody yet suggested it, so I will: Browser as UI platform. You could write your app in Clojure, including an HTTP server and then develop the UI using anything from HTML to hiccup, ClojureScript and any of the billions of JS libaries you need. If you wanted consistent browser behaviour and "desktop app look'n'feel" you could bundle chrome with your app.
This seems to be how Light Table is distributed.
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.
There is a wrapper for MigLayout in clojure contrib. You can also take a look at this gist. 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)))
I would rather go for clojurefx, it is a bit premature, but it does work and saves you time.
I started my GUI with seesaw and then tried another component in clojurefx.
I have finished both, and I am convinced that I am going to refactor the seesaw one to clojurefx.
After all, JavaFX is the way to go forward.
It feels lighter than seesaw. Or at least, writing it..
Bindings work, listeners work, most of the component work, otherwise, just use one of the macros to create a constructor for that particular case and job done. Or, if you find it difficult, write some methods in Java and ask for help to improve clojurefx.
The guy who wrote clojurefx is busy at the moment, but you can fork the project and do some fixes.
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.
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)))
I asked myself the same question of writing a GUI in Clojure with Swing and came up with the library signe
It lets you use represent your domain model as a single Clojure data structure wrapped inside an atom.
See the examples here.
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.
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.
My preferred Clojure UI environment uses IO.js (Node for ES6) + Electron (Container) + Quiescent (ReactJS wrapper).
So I didn't see Fn-Fx on this list, from Timothy Baldridge (halgiri). This is a Clojure library providing a functional abstraction over JavaFX.
It can be found on Github at https://github.com/halgari/fn-fx.
To use, make sure you are using a recent version of Java (1.8 90+) and add a dependency to the github repo by adding the following to your project.clj:
:plugins [[lein-git-deps "0.0.1-SNAPSHOT"]]
:git-dependencies [["https://github.com/halgari/fn-fx.git"]]
I have tried it, and it works out of the box.
Clojure and SWT is the best approach for doing GUI(s). Essentially, SWT is a plug and play style approach for developing software.
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 :)
cljfx is described as a
Declarative, functional and extensible wrapper of JavaFX inspired by better parts of react and re-frame
and JavaFx as
... an open source, next generation client application platform for desktop, mobile and embedded systems built on Java. It is a collaborative effort by many individuals and companies with the goal of producing a modern, efficient, and fully featured toolkit for developing rich client applications.
Its creator uses it to build reveal, and a hackernews demo that features various capabilities and some bundling for multiple OSs via jpackage.
You can get Clojure REPL-driven development with this by leveraging JavaFX to build UIs for desktop, mobile, and web.
Related
In Clojure for Java Programmers Part 1 talk Rich Hickey mentions this as one of the benefits of Clojure:
If you build an application with some access to the ability to load
code - either a remote repl connection or some way to do that. Your
running production systems will have this capability to have fixes
loaded into running programs.
I'm wondering how easy it is in practice. Let's say I know there is a bug in one function and I want to redefine/override it in production via remote repl
Is it possible?
Will the overridden version stay active after I exit the repl?
Is this behavior in all JVM application containers?
I don't have any experience of using JVM in production and that's the reason for asking this question.
Is it possible?
Yes, I would recommend watching The Joys and Perils of Interactive Development - Stuart Sierra he tells a story of NASA hotfixing a satellite in space using the REPL.
Will the overridden version stay active after I exit the repl?
When you reevaluate the function the changes will apply everywhere so for example
(defn add1 [x]
(+ x 2))
(defn foo [x]
(add1 x))
(foo 1)
Notice (foo 1) => 3 if you fix and reevaluate add1 then run again (foo 1) => 2
I'm new to Clojure, and after too much of my life have been already wasted on waiting for Leiningen to run my code, I'm trying to move to Cake. While Cake's persistent JVM loads up blazing fast - it presents a bigger problem - my functions are also persistent!
To demonstrate the problem, I've started a cake project(using cake new mess-up-with-cake), and wrote this in core.clj:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
)
(println "I'm in core.clj, not inside in any function")
And this is project.clj:
(defproject mess-up-with-cake "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[clojure "1.2.0"]])
(use 'mess-up-with-cake.core)
(deftask my-task
(println "I'm in my task")
(main-function)
)
When running it with cake my-task, I get:
I'm in core.clj, not inside in any function
I'm in my task
I'm in the main function
No surprise here.
Now, I've changed core.clj to this:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
(println "I've made a change in the main function")
)
(println "I'm in core.clj, not inside in any function")
(println "I've made a change outside the main function")
And when I run it, I get
I'm in core.clj, not inside in any function
I've made a change outside the main function
I'm in my task
I'm in the main function
core.clj was clearly reloaded, but the change I've made inside the main function was not printed! Only when I stop the JVM with cake kill and rerun it I get the desired result - but if I have to restart the JVM every time I change a function, I might as well go back to lein...
Any idea how to force cake to reload my functions(and only my functions - reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM..)?
This may not directly answer your question, though I hope it helps:
It sounds like your workflow if you where using leiningen would be to run:
lein run
wait for the JVM to start up .... get bored ...
observe result
edit code
repeat
This is a very common pattern in most languages and it's occasionally used for Clojure development (and Cake is very helpful here). It is much more common for Clojure development to use a single instance of the project and connect the editor to that instance using nrepl (or Slime and Swank). Because most everyone leaves the project running while they do the development not many people feel this pain and so the solutions are not as good in my opinion. Cake has largely been merged into Leiningen and the future direction of the Cake project is not clear to me (I could very well be wrong on this point). Of the Clojureians I know, all of them have moved to Leiningen and connect to their project from an editor like Emacs or vim.
a common workflow is:
start Emacs
M-x nrepl-jack-in
Ctrl-c Crtl-l to reload all the namespace and all it's dependent namespaces (this is close to a solution to your problem)
hack, load, repeat ;-)
This workflow is not Emacs or VI specific, the same method is used from Eclipse and Intelij
re: " reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM".
I find it to be no more than two seconds even with my larger projects
I used to struggle with the slow JVM startup speed as well, and had mixed success with Cake. You might want to take a look at the excellent autoexpect plugin for Leiningen, explained in some length in the author's blog post. Basically autoexpect reloads your code every time the working directory tree is updated (and evaluates any expect clause, reporting any test failures). Makes continuous testing a dream -- I sometimes have two shells going in Emacs -- one for the output of lein autoexpect, one for a connected REPL to send snippets of code to as the other poster is suggesting.
I like the continuous testing style so much I wrote a similar utility in Python for my non-Clojure development (described in this blog post) -- for Clojure, I use autoexpect.
When using the leiningen REPL, is there a way to make a file or ns automatically reload in the repl on file save. Currently I reload the ns by typing the following in the repl - (use 'sample.ns :reload-all).
However can I have it reload automatically on file save ?
You can easily reuse the code from duct framework.
You will need only hawk files watcher.
Here is how it can be looks like:
(defn- clojure-file? [_ {:keys [file]}]
(re-matches #"[^.].*(\.clj|\.edn)$" (.getName file)))
(defn- auto-reset-handler [ctx event]
(binding [*ns* *ns*]
(clojure.tools.namespace.repl/refresh)
ctx))
(defn auto-reset
"Automatically reset the system when a Clojure or edn file is changed in
`src` or `resources`."
[]
(hawk.core/watch! [{:paths ["src/" "resources/" "dev/src/" "dev/resources/"]
:filter clojure-file?
:handler auto-reset-handler}]))
Clojure-Watch library does what you need. It observes a file and performs some action. In your case, an action would be to reload a namespace from that file. Also, it requires to write some initial code to launch the observer.
This way seems a bit complicated to me. Plain REPL launched directly from Lein is not effective way to develop. You better to use some Clojure-friendly editor like Emacs or Lightable.
Most major editors support custom hotkey bindings and have a Clojure plugin that allows you to connect to the active REPL over the network (via "nREPL"). Personally, I use vim and therefore use vim-fireplace for this purpose.
This means you can have a custom hotkey for reloading whatever file you're editing as you edit it. From there, it's typically trivial to add a custom on-save hook that does the reloading.
What's the best way to make code run at regular intervals in Clojure ? I'm currently using java.util.concurrent.ScheduledExecutorService, but that's Java - is there a Clojure way of scheduling code to run at regular intervals, after a delay, cancellably ? All the Clojure code examples I've seen use Thread/sleep, which also seems too Java.
Well worth looking at the source code for Overtone, in particular the code for scheduling events at a particular time.
It's a music synthesis system so you have to hope they have the timing code right!!
Also they have helpfully separated the timing code out into a separate project (overtone/at-at) so that you can easily import it if you want. This provides a nice Clojure wrapper to the underlying Java libraries (i.e. ScheduledThreadPoolExecutor and friends). The syntax is like this:
;; run some-function every 500ms
(every 500 some-function)
You can also shedule events at specific times:
;; run some-other-function 10 seconds from now
(at (+ 10000 (now)) some-other-function)
From the clojure website http://clojure.org/concurrent_programming:
In all cases, Clojure does not replace the Java thread system, rather it works with it. Clojure functions are java.util.concurrent.Callable, therefore they work with the Executor framework etc.
It sounds like you are already doing it the right way.
(import 'java.util.concurrent.Executors)
(import 'java.util.concurrent.TimeUnit)
(.scheduleAtFixedRate (Executors/newScheduledThreadPool 1)
#(println "Hello") 0 5 TimeUnit/SECONDS)
I answered my own question # Implementing a cron type scheduler in clojure
maybe cronj might help?
The "tools.timer" library is a Java Timer wrapper: https://github.com/Ruiyun/tools.timer
It is very easy to use:
(use 'ruiyun.tools.timer)
(run-task! #(println "Say hello every 5 seconds.") :period 5000)
I have an application in clojure making heavy use of a Java framework called Vaadin. Vaadin uses several callbacks using the Java "proxy" feature of clojure. However, every time a proxy is called in a clojure function there is a significant delay (100s of milliseconds sometimes). Is there any way I can speed this up?
My understanding is that the new reify macro is faster than proxy. You can use it if you only need to implement a single interface.
For example, if you need to implement a java.awt.event.ActionListener you can use code like the following:
(import 'java.awt.event.ActionListener 'javax.swing.JButton)
(let [a-button (JButton. "Click Me")]
(.addActionListener a-button
(reify ActionListener
(actionPerformed [this ev] (comment do something interesting)))))