Say you want to draw stuff…

I recently had to deal with troubles involving Swing and the Event Dispatch Thread (EDT for friends) at work.

Details are shrouded in secrecy, and flying monkeys will be rightfully dispatched, should I delve on them, but it suffices to say, they had to do with graphics and EDT concurrency.

Plain Java solved all those problems alright, mostly with the judicious use of lazy initialization and and the invokeLater utility method and yet, despite the whole bunch of Java 8 features, the implementation feels a bit clunky, wherever anything, but the shortest method references, is to be used.

Incidentally, I started working on graphics at home, and ended up with similar issues, but this time, with Clojure.

While Clojure can’t do anything unique or special, when compared to Java, it provides tools that allow to actually play with graphics, and solve some of the thread-related issues more elegantly.

Let’s play a bit with Graphics on Clojure, shall we?!

REPL-oriented graphics

Clojure coding is not Clojure coding without a REPL running, so let’s start one (maybe in CIDER mode?), and see if we can create a small frame to write into…

> (def test-frame (doto (JFrame.)
                          (.setSize 320 200)
                          (.show)))
#'some-namespace/test-frame

And a brand new Frame appears, ready to do our bidding:

easy as pie!

Let’s scribble on it: I’m not Pablo Picasso, so I’ll just change the background (you’ll see a lot of background changes, as a remainder that – as I have just mentioned – “I’m not Pablo Picasso”).

  
> (.setBackground (.getGraphics test-frame) Color/RED)

And surprise!

 

…nothing happens.

Each JComponent has its own paint method, which is called at every repaint and will happily overwrite whatever we throw at the object with our flimsy drawing attempt.

Fat bastard with 'you bastard' caption

 

We could override the base paint method, and create a new object every time we want to experiment, but honestly this is sooo 1995!

Even vanilla Java coders have better means now, with the judicious use of a Consumer<Graphics> interface, so we’ll do pretty much what they do nowadays:

> (defn show-frame
  ([width height] (show-frame width height nil))
  ([width height paint-f]
   (doto (proxy [JFrame] []
           [paint [graphics]
            (if paint-f
              (paint-f this graphics))])
     (.setSize (Dimension. width height))
     (.show))))
#'some-namespace/show-frame 

show-frame accepts an optional method that will dictate how the component is painted.

Passing a method reference will ensure that changing the paint method definition will be “seen” by the class:

>  (defn my-paint [this graphics] (.setBackground this Color/BLACK))
#'some-namespace/my-paint
> (def frame (show-frame 320 200 my-paint))
#'some-namespace/frame

Good enough:

black JFrame

Let’s see what we can do interactively:

> (defn my-paint [this graphics] (.setBackground this Color/MAGENTA))  
#'some-namespace/my-pain
> (.repaint frame)
nil

 

Et voilà: interactive REPL scribbling enabled (the annoying color is a bonus)!

magenta JFrame

And yet I might have forgot something…

Every Damn Time

It’s counter-intuitive, but even JComponent instantiating – no matter how basic the component is – should go into the Event Dispatch Thread, as this Stack Overflow answer points out.

Luckily enough, we Clojure programmers can borrow SwingUtils.invokeLater and SwingUtils.invokeAndWait, so no big deal, right?!

> (SwingUtilities/invokeAndWait (fn [] (show-frame 320 200)))
nil

The frame appears, but the syntax is a bit on the hideous side, so let’s sweeten it a bit:

> (defmacro invoke-and-wait [ & forms]
       `(SwingUtilities/invokeAndWait (fn [] ~@forms)))
#'some-namespace/invoke-and-wait

Which enables us to a slightly shorter form (which can be incidentally used with multiple forms or without one too):

> (invoke-and-wait (show-frame 320 200))
nil

Let’s see: we are able to created our frame in the right thread, and to draw on it interactively, so home base!

WAIT A SECOND!!!

The invokeAndWait method returned nil!

Despite being the SwingUtils.invokeAndWait a synchronous method, it doesn’t accept a supplier and return a generic as it could, but — probably for historical reasons — it operates on a Runnable and returns void.

This is OK for the typical use, that is, to trigger some UI change that has only side effects, but what if we want to use it to create a JComponent interactively?

Here is the answer:

>  (defmacro invoke-and-wait
    "Invokes the forms within an invokeAndWait method, and returns the value of the last form."
    [& forms]
    `(let [result# (atom nil)]
       (SwingUtilities/invokeAndWait (fn [] (reset! result# ((fn [] ~@forms)))))
       @result#))

With this new macro, (invoke-and-wait (show-frame 320 200)) returns the frame, which we can store wherever we want, for later use.

The promise of some very Graphics content

What if we don’t want to use the EDT thread in lockstep?

Abusing invokeAndWait leads to unresponsive interfaces: we want to take advantage of both the thread safety AND the concurrency EDT would enable us to.

We want to eat the cake, we want to have it, and we want it now.

We can use a slightly modified version of the last macro to invoke the invokeLater returning a special value (that is, a promise).

The promise will block until a value has been delivered to it, when de-referenced:

  (defmacro invoke-later
  "Invokes the forms into a invokeLater, returns a promise with the result of the last form"
  [& forms]
  `(let [result# (promise)]
  (SwingUtilities/invokeLater (fn [] (deliver result# ((fn [] ~@forms)))))
  result#))

Invoking the creation of a frame will still do the job, and return something like:

> (invoke-later (show-frame 320 200))
#promise[{:status :pending, :val nil} 0x248259a6]

Which will block any attempt to use the value, until the operation is completed, and the value properly realized.

This last macro is also rather general, and it will make the invoke-and-wait one actually redundant, as the latter can be reduced to a call of this one, followed by a @ operator on the result:

>  @(invoke-later (show-frame 320 200))
#object[clojure_scratchpad.graphics.proxy$javax.swing.JFrame$ff19274a 0x7a35ae23 "clojure_scratchpad.graphics.proxy$javax.swing.JFrame$ff19274a[frame13,0,27,320x200,layout=java.awt.BorderLayout,title=,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,5,25,310x170,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]"]

Now we can play interactively (and safely) with the Graphics2D class, and experiment with the code — as it suits to all good Clojure programmers — as I did with this example:

Green still life painting

 

Nope. This is an actual Picasso (“Green still life [1914]”)…

Leave a Reply

Your email address will not be published. Required fields are marked *