cljfx

https://github.com/cljfx/cljfx
2020-10-01T08:51:03.047100Z

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

vlaaad 2020-10-01T08:57:56.048300Z

@huxley yep, possible: effects are treated as a collection of tuples, it doesn’t have to be a map, e.g. [[:dispatch ...] [:dispatch ...]]

2020-10-01T08:59:31.048500Z

@vlaaad Can I find a code example somewhere?

vlaaad 2020-10-01T09:00:46.049400Z

I don’t think there are code examples, just return a coll of tuples instead of a map in event handler 🙂

vlaaad 2020-10-01T09:02:00.049700Z

there are only examples returning maps. e.g. https://github.com/cljfx/cljfx/blob/master/examples/e18_pure_event_handling/events.clj#L15-L20

2020-10-01T09:08:26.050100Z

It took me a while, but I think I understand ; )

👍 1
2020-10-01T09:11:09.050400Z

I did something similar, but I thought that maybe there is a more obvious solution, for example something like that.

2020-10-01T09:11:35.050600Z

{:fx/type          :button
  :text            "button"
  :on-action       [{:event/type :evt-1}
                    {:event/type :evt-2}
                    {:event/type :evt-3}]}

vlaaad 2020-10-01T09:12:16.051300Z

ah, no, there is nothing like that unfortunately, you can only have a single event in description

2020-10-01T09:13:01.052100Z

Okay, it's awesome anyway. 😉

vlaaad 2020-10-01T09:13:03.052300Z

I have an issue to make event handlers more free-form: https://github.com/cljfx/cljfx/issues/48

vlaaad 2020-10-01T09:13:21.052800Z

but I’m not working on it 🙂

vlaaad 2020-10-01T09:14:14.053500Z

I’m not doing anything about it because it’s wasn’t that big of an issue in practice

2020-10-01T09:15:29.053700Z

Thanks for your help and your time

vlaaad 2020-10-01T09:15:44.054Z

you are welcome 🙂

danielsz 2020-10-01T12:01:17.058100Z

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.

vlaaad 2020-10-01T12:04:04.059700Z

java 11? call (javafx.application.Platform/startup #()) before importing classes from javafx.scene.control package

danielsz 2020-10-01T12:04:22.060200Z

Yes, of course. I do that.

vlaaad 2020-10-01T12:04:27.060400Z

ah, hmmm

vlaaad 2020-10-01T12:04:59.060900Z

just to be clear — you do it before import, not before creating instance?

vlaaad 2020-10-01T12:05:35.061500Z

unfortunately, I can’t help with nrepl as I don’t use it

danielsz 2020-10-01T12:07:06.062600Z

The import statement are in the ns declaration, the platform initialization is a top-level definition.

vlaaad 2020-10-01T12:07:26.063200Z

top-level definition before ns call?

danielsz 2020-10-01T12:08:03.063800Z

No, it's a function that runs on the nREPL, so it runs after the import.

vlaaad 2020-10-01T12:09:22.064800Z

hm, I would guess this is the problem — JavaFX runtime has to be started before javafx.scene.control.* classes are imported

danielsz 2020-10-01T12:10:37.066500Z

I tried at the REPL, initialized the JavaFX runtime, then imported the control at the REPL, still the same error.

vlaaad 2020-10-01T12:12:12.068300Z

hmm, actually just running (import 'javafx.scene.control.Label) does not fail in a freshly-started repl with JavaFX on the classpath

danielsz 2020-10-01T12:12:26.068700Z

Exactly.

vlaaad 2020-10-01T12:12:27.068800Z

can you share the whole stacktrace?

danielsz 2020-10-01T12:12:54.069500Z

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)

vlaaad 2020-10-01T12:13:54.070500Z

hmm, and that’s it? no causes? no extra output in stderr?

danielsz 2020-10-01T12:14:12.070800Z

No. It's definitely a nREPL specific problem, just asking if anyone has seen this before.

danielsz 2020-10-01T12:14:38.071200Z

nREPL is modifying the class loading mechanism.

danielsz 2020-10-01T12:15:29.072200Z

And to be clear, I'm not using cljfx neither. It's just plain interop.

vlaaad 2020-10-01T12:15:49.072700Z

yeah, I see 🙂

scythx 2020-10-01T12:16:18.073Z

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)}]}]}}})

scythx 2020-10-01T12:16:35.073500Z

Am i missing something?

vlaaad 2020-10-01T12:17:09.073800Z

day of cljfx issues 😄

🦜 4
vlaaad 2020-10-01T12:18:05.074800Z

@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

vlaaad 2020-10-01T12:19:20.075900Z

perhaps setting default user agent stylesheet might help with nrepl ¯\(ツ)

vlaaad 2020-10-01T12:19:55.076700Z

@raefaldhiamartya can you share the whole stacktrace?

vlaaad 2020-10-01T12:20:24.077200Z

do you call .getScene somewhere?

vlaaad 2020-10-01T12:21:04.078200Z

ah, there is this call in the example code https://github.com/cljfx/cljfx/blob/master/examples/e33_file_chooser.clj#L12-L17

scythx 2020-10-01T12:21:47.079600Z

yes getscene only in that code, here's all i have

scythx 2020-10-01T12:21:47.079700Z

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)

vlaaad 2020-10-01T12:22:10.080100Z

Looks like MenuItem does not have .getScene method that is called on an event target by the handler

vlaaad 2020-10-01T12:23:16.080600Z

and you need to pass a parent window to .showOpenDialog

vlaaad 2020-10-01T12:24:38.081500Z

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

1
scythx 2020-10-01T12:25:09.081800Z

ahhh alright then, thank you!

danielsz 2020-10-01T12:27:26.081900Z

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.

vlaaad 2020-10-01T12:29:38.082200Z

oh right, it’s mentioned in the readme 😄

vlaaad 2020-10-01T12:29:56.082400Z

haven’t seen that, definitely looks like a classloader hack 🙂

danielsz 2020-10-01T12:39:09.082700Z

Yup, all bets are off at that point. 😕

danielsz 2020-10-01T12:39:33.082900Z

nREPL is guilty of the same folly.

danielsz 2020-10-01T12:43:45.083100Z

Here's the interesting thing. A "hello world" program with cljfx works at a nREPL.

danielsz 2020-10-01T12:44:24.083300Z

Including a Label control.

danielsz 2020-10-01T12:45:16.083500Z

My super basic interop throws this class not found error. And the maddening thing is: not all the time.

danielsz 2020-10-01T12:45:45.083700Z

Sometimes it all works.

vlaaad 2020-10-01T12:46:47.083900Z

¯\(ツ)

danielsz 2020-10-01T12:47:01.084100Z

Exactly.

vlaaad 2020-10-01T12:47:12.084300Z

cljfx FTW 😄

danielsz 2020-10-01T12:47:15.084500Z

Thanks for your patience,.

danielsz 2020-10-01T12:47:20.084700Z

Yes!

danielsz 2020-10-01T12:47:56.084900Z

I'll take this opportunity to congratulate you on the work. I've been reading the source code. Very elegant. Kudos!

vlaaad 2020-10-01T12:48:17.085100Z

thanks for the compliment! ^_^