Unfortunately, I did not find information in the examples or in the source code, so I will ask.
Is it possible to fire several events at once? I mean something like :dispatch-n
in re-frame
@huxley yep, possible: effects are treated as a collection of tuples, it doesn’t have to be a map, e.g. [[:dispatch ...] [:dispatch ...]]
@vlaaad Can I find a code example somewhere?
I don’t think there are code examples, just return a coll of tuples instead of a map in event handler 🙂
there are only examples returning maps. e.g. https://github.com/cljfx/cljfx/blob/master/examples/e18_pure_event_handling/events.clj#L15-L20
It took me a while, but I think I understand ; )
I did something similar, but I thought that maybe there is a more obvious solution, for example something like that.
{:fx/type :button
:text "button"
:on-action [{:event/type :evt-1}
{:event/type :evt-2}
{:event/type :evt-3}]}
ah, no, there is nothing like that unfortunately, you can only have a single event in description
Okay, it's awesome anyway. 😉
I have an issue to make event handlers more free-form: https://github.com/cljfx/cljfx/issues/48
but I’m not working on it 🙂
I’m not doing anything about it because it’s wasn’t that big of an issue in practice
Thanks for your help and your time
you are welcome 🙂
As documented in https://github.com/cljfx/cljfx#aot-compilation-is-complicated, the classes from javafx.scene.control require JavaFX runtime to be running by accessing it in Control's static initializer. I've encountered a variation on this issue that manifests itself in a nREPL session. After initializing the toolkit, any code running on the Javafx Application Thread that references a control throws an error.
Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: Could not initialize class javafx.scene.control.Label
The following code block runs fine because it doesn't reference a control.
(let [stage (Stage.)
stack-pane (StackPane.)
scene (Scene. stack-pane 640 480)]
(.setScene stage scene)
(.show stage))
An empty window appears.
However, the following code block throws the aforementioned error because it references a control.
(let [stage (Stage.)
label (Label. "Hello")
stack-pane (StackPane. (into-array Node [^Label label]))
scene (Scene. stack-pane 640 480)]
(.setScene stage scene)
(.show stage))
To be clear, this issue has nothing to do with cljfx. Most likely it is a problem with nREPL and its class loading. The problem doesn't appear with inf-clojure either. I'm asking it here in case this resonates with someone.java 11? call (javafx.application.Platform/startup #())
before importing classes from javafx.scene.control
package
Yes, of course. I do that.
ah, hmmm
just to be clear — you do it before import, not before creating instance?
unfortunately, I can’t help with nrepl as I don’t use it
The import statement are in the ns declaration, the platform initialization is a top-level definition.
top-level definition before ns
call?
No, it's a function that runs on the nREPL, so it runs after the import.
hm, I would guess this is the problem — JavaFX runtime has to be started before javafx.scene.control.* classes are imported
I tried at the REPL, initialized the JavaFX runtime, then imported the control at the REPL, still the same error.
hmm, actually just running (import 'javafx.scene.control.Label)
does not fail in a freshly-started repl with JavaFX on the classpath
Exactly.
can you share the whole stacktrace?
Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: Could not initialize class javafx.scene.control.Label
at caonima.repl$foo$f__15007__auto____15021.invoke(repl.clj:35)
at clojure.lang.AFn.run(AFn.java:22)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
at java.base/java.lang.Thread.run(Thread.java:832)
hmm, and that’s it? no causes? no extra output in stderr?
No. It's definitely a nREPL specific problem, just asking if anyone has seen this before.
nREPL is modifying the class loading mechanism.
And to be clear, I'm not using cljfx neither. It's just plain interop.
yeah, I see 🙂
Hello, i want to create menu-item to use file chooser, so i modified the root-view of https://github.com/cljfx/cljfx/blob/master/examples/e33_file_chooser.clj But for the menu-item it gave me
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: No matching field found: getScene for class javafx.scene.control.MenuItem
(defn root-view [{:keys [image-path content]}]
{:fx/type :stage
:title "Textual file viewer"
:showing true
:width 800
:height 600
:scene {:fx/type :scene
:root {:fx/type :v-box
:children [{:fx/type :menu-bar
:menus [{:fx/type :menu
:text "File"
:items [{:fx/type :menu-item
:text "Open image ..."
:on-action {::event ::open-image}}]}]}
;; The button works but not for the menu above
{:fx/type :h-box
:spacing 15
:alignment :center-left
:children [{:fx/type :button
:text "Open file..."
:on-action {::event ::open-image}}
{:fx/type :label
:text (str image-path)}]}]}}})
Am i missing something?
day of cljfx issues 😄
@danielsz just in case — the problems with JavaFX initialization and controls I had had to do with this code in Control static initializer: https://github.com/openjdk/jfx/blob/d10f948ee7380ac73bc4e2d5bff1caba50fe00a8/modules/javafx.controls/src/main/java/javafx/scene/control/Control.java#L98-L100
perhaps setting default user agent stylesheet might help with nrepl ¯\(ツ)/¯
@raefaldhiamartya can you share the whole stacktrace?
do you call .getScene
somewhere?
ah, there is this call in the example code https://github.com/cljfx/cljfx/blob/master/examples/e33_file_chooser.clj#L12-L17
yes getscene
only in that code, here's all i have
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: No matching field found: getScene for class javafx.scene.control.MenuItem
at clojure.lang.Reflector.getInstanceField(Reflector.java:397)
at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:440)
at clojure.io.github.raefaldhia.image_processing.core$eval17490$fn__17492.invoke(core.clj:13)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at cljfx.event_handler$wrap_co_effects$fn__13793.invoke(event_handler.clj:10)
at cljfx.event_handler$wrap_effects$dispatch_sync_BANG___13806.invoke(event_handler.clj:27)
at cljfx.event_handler$wrap_effects$dispatch_sync_BANG___13806.invoke(event_handler.clj:25)
at cljfx.lifecycle$make_handler_fn$fn__13457.invoke(lifecycle.clj:128)
at cljfx.coerce$event_handler$reify__13022.handle(coerce.clj:135)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.control.MenuItem.fire(MenuItem.java:459)
at com.sun.javafx.scene.control.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1380)
at com.sun.javafx.scene.control.ContextMenuContent$MenuItemContainer.lambda$createChildren$12(ContextMenuContent.java:1333)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3890)
at javafx.scene.Scene.processMouseEvent(Scene.java:1885)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2618)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:409)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:299)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:447)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:412)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:446)
at com.sun.glass.ui.View.handleMouseEvent(View.java:556)
at com.sun.glass.ui.View.notifyMouse(View.java:942)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
at java.base/java.lang.Thread.run(Thread.java:834)
Looks like MenuItem does not have .getScene
method that is called on an event target by the handler
and you need to pass a parent window to .showOpenDialog
…
Either you should find another way to get a hold on the window from the event, or you should use (javafx.stage.Window/getWindows)
to get a window from there
ahhh alright then, thank you!
Yes, that is indeed why the JavaFx runtime needs to be running when compiling those classes. You've explained it nicely in the README. I thank you for that. Have you noticed what happens https://github.com/openjdk/jfx/blob/d10f948ee7380ac73bc4e2d5bff1caba50fe00a8/modules/javafx.controls/src/main/java/javafx/scene/control/Control.java#L119 in that same class? It's a class loading hack. nREPL does its own class loading hacks and I suspect they don't see eye to eye.
oh right, it’s mentioned in the readme 😄
haven’t seen that, definitely looks like a classloader hack 🙂
Yup, all bets are off at that point. 😕
nREPL is guilty of the same folly.
Here's the interesting thing. A "hello world" program with cljfx
works at a nREPL.
Including a Label control.
My super basic interop throws this class not found error. And the maddening thing is: not all the time.
Sometimes it all works.
¯\(ツ)/¯
Exactly.
cljfx FTW 😄
Thanks for your patience,.
Yes!
I'll take this opportunity to congratulate you on the work. I've been reading the source code. Very elegant. Kudos!
thanks for the compliment! ^_^