Getting a result from a swing JDialog

572 views
Skip to first unread message

Tim Martin

unread,
Feb 7, 2009, 6:15:44 PM2/7/09
to Clojure
Hi all,

I was wanting to create a dialog box in a (predominantly command-line)
application where the action of the user on the dialog box is returned
to the code that requested the dialog so we can branch based on the
selection. It seems the most natural way of doing this in a functional
language is to block until the dialog box is closed and then return a
value, rather than messing with mutable state. This fits in well with
what I want to happen in my program.

I can do this quite easily with a JOptionPane, which has the right
semantics for me, and can return a single value to indicate what
option was chosen. So far so good.

However, if I want more control over the layout and content of the
dialog, I seem to be best served by building it myself out of a
JDIalog [1]. I've got code that creates the JDialog and then blocks
until it is closed, which I can control with a button and an
ActionListener in the obvious way. However, the snag is that it
doesn't return the outcome. The interface of JDialog seems to be built
around the idea of having mutable objects and state, and having an
action listener that can mutate the object and a getter method to find
the value assigned in the listener.

I imagine I can get round this by writing a thin wrapper for the
JDialog that will handle the state in Java, but is there a pure
Clojure way to do this kind of thing? [2] If not, is this (unlikely) a
general problem with GUI programming in functional languages or (most
likely, I assume) a paradigm mismatch between Swing and functional
languages. If the latter, would the Clojure community be well-served
by a standard library of shims for making Swing fit better into the
functional mould?

Tim

[1] My experience of Swing is minimal, so I'm ready to be corrected if
this turns out to be terribly naive.

[2] Aside from unscalable hacks like having a package-level mutable
ref that can be updated from within a listener

Jeffrey Straszheim

unread,
Feb 8, 2009, 8:12:56 PM2/8/09
to clo...@googlegroups.com
A JDialog is going to run on the GUI thread and you can't change that.

There are various concurrency tools in Java that will give you what you want.  The easiest is to wait create a SynchronousQueue.  Check the Java API docs.

chris

unread,
Feb 9, 2009, 12:04:34 PM2/9/09
to Clojure
I would create a ref in the let statement that is launching the
dialog. Then create a countdown latch and launch the dialog using
SwingUtilities/invokeLater. Ensure the ref is set (dosync ...) and
the latch is counted when the dialog is closed. Now you have a
synchronous result from your asynchronous dialog.

Chris

On Feb 8, 6:12 pm, Jeffrey Straszheim <straszheimjeff...@gmail.com>
wrote:

Phlex

unread,
Feb 11, 2009, 7:43:27 AM2/11/09
to clo...@googlegroups.com
Tim Martin wrote:
> Hi all,
> ...
>
The JDialog contructor takes a parameter that will tell it to be a modal
window.

(ns cara.gui.dialog-test
(:import [javax.swing JDialog JTextField JButton AbstractAction]))

(defn- create-and-show [data-ref]
(let [dialog (new JDialog (@data-ref :owner) true) ;;second parameter
says block on setVisible
text-field (doto (new JTextField)
(.setColumns 40)
(.setText (@data-ref :text)))
ok-btn (doto (new JButton "OK")
(.addActionListener
(proxy [AbstractAction] []
(actionPerformed [evt]
(dosync (alter data-ref assoc
:text (.getText text-field)))
(.dispose dialog)))))]
(doto dialog
(.setLayout (new java.awt.FlowLayout))
(.add text-field)
(.add ok-btn)
(.pack)
(.setVisible true))
(@data-ref :text)))

(defn user-string [owner base-string]
(create-and-show (ref {:owner owner :text base-string})))

cara.gui.dialog-test=> (user-string nil "hallo world")
;; a dialog shows up, i change the text then press ok
"hello world"
cara.gui.dialog-test=>

I don't like this very much as there's mutable state in the data-ref,
but it does the job.
If someone else have a better idea, let me know!

hth,
Sacha

Reply all
Reply to author
Forward
0 new messages