Bind segment of atom to bindable

60 views
Skip to first unread message

Nikola Vojičić

unread,
Mar 13, 2019, 9:00:50 PM3/13/19
to seesaw-clj
I would like to have an atom representing (most of) the UI state.
Values in forms, tabs etc. should change when that atom changes and vice versa.
I'm not sure how to bind UI component to some specific key-value of a nested map inside atom and not to the whole atom.

(def state
  (atom
   {:x 0
    :y "foo"
    :z {:q [1 2 3]
        :w [3 2 1]}}))

I can, for example, bind some input text field to the :y in state via b-swap! with assoc :y, so that it changes the state on input.
But I need bidirectional behaviour - when state :y changes, input text should also be updated.
One way to do that is to wrap each value with an atom:

(def state
  {:x (atom 1)
   :y (atom "foo")
   :z {:q (atom [1 2 3])
       :w (atom [3 2 1])}})

Binding is much simpler now...

(ssb/bind txt (:state))
(ssb/bind (:state) txt)

But the state is complex.
Is it thread safe from the Swing point of view?
Application occasionally breaks with the following exception (full stack trace here):

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
at java.desktop/javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1349)
at java.desktop/javax.swing.text.AbstractDocument.remove(AbstractDocument.java:590)
at seesaw.bind$eval15943$fn__15948.invoke(bind.clj:167)
at seesaw.bind$eval15805$fn__15806$G__15796__15813.invoke(bind.clj:23)
at seesaw.bind$bind$fn__15868.invoke(bind.clj:88)
at seesaw.bind$eval15911$fn__15912$bindable_atom_watcher__15913.invoke(bind.clj:138)
at clojure.lang.ARef.notifyWatches(ARef.java:81)
at clojure.lang.Atom.reset(Atom.java:157)
at clojure.core$reset_BANG_.invokeStatic(core.clj:2381)
at clojure.core$reset_BANG_.invoke(core.clj:2376)

... even though I am not mutating anything from multiple threads.

abacus

unread,
Mar 14, 2019, 4:15:35 AM3/14/19
to seesaw-clj
Rule of thumb: keep very quiet in the handler of an event from Swing. Instead of causing a ruckus in the handler, use invokeLater to enqueue effects to be done at a time when Swing is not in the event-delivering mode.

Nikola Vojičić

unread,
Mar 14, 2019, 6:18:00 AM3/14/19
to seesa...@googlegroups.com
Sorry, this exception was caused by my stupid mistake: forgetting to reset the state before running UI from the REPL.

On Thu, Mar 14, 2019 at 9:15 AM abacus <phill...@gmail.com> wrote:
Rule of thumb: keep very quiet in the handler of an event from Swing. Instead of causing a ruckus in the handler, use invokeLater to enqueue effects to be done at a time when Swing is not in the event-delivering mode.

--
You received this message because you are subscribed to the Google Groups "seesaw-clj" group.
To unsubscribe from this group and stop receiving emails from it, send an email to seesaw-clj+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nikola Vojičić

unread,
Mar 14, 2019, 6:24:11 AM3/14/19
to seesa...@googlegroups.com
Also, the second state example (map holding atoms) is not complex at all, atoms are not nested.
Reply all
Reply to author
Forward
0 new messages