I created a new Clojure app with clojure -Tclj-new app :name myname/myapp
and added the javafx deps to deps.edn
org.openjfx/javafx-controls {:mvn/version "17.0.2"}
org.openjfx/javafx-base {:mvn/version "17.0.2"}
org.openjfx/javafx-graphics {:mvn/version "17.0.2"}
org.openjfx/javafx-media {:mvn/version "17.0.2"}
org.openjfx/javafx-web {:mvn/version "17.0.2"}
I copied the initialization of a UI using JavaFX, extending the class Application
.
(ns myname.myapp
(:import
(javafx.application Application)
(javafx.scene Scene)
(javafx.scene.layout VBox)
(javafx.scene.control Label)
(javafx.stage Stage))
(:gen-class :extends javafx.application.Application))
(def app (atom nil))
(defn -start [this stage]
(let [root (VBox.)]
(reset! app this)
(.setTitle stage "Hello From Clojure!")
(.add (.getChildren root) (Label. "Hello World"))
(.show stage)))
(defn -main [& args]
(Application/launch myname.myapp args))
I cannot run the project. With clj -M:run-m
it returns
Syntax error (ClassNotFoundException) compiling at (myname/myapp.clj:20:3). myname.myapp
It seems that Clojure is not generating any class since no folder target
is created. I'm using Clojure 1.11.1
on macOS 12.4
I think you really have to create uberjar- you can also use this command:
lein uberjar
and then use java -jar your-app-standalone.jar
in the folder with the created jar (probably target/uberjar/
).
Also, if you want to display your Label
, you have to create Scene
and add that label there. This works:
(ns myapp.core
(:import
(javafx.application Application)
(javafx.scene Scene)
(javafx.scene.layout VBox)
(javafx.scene.control Label))
(:gen-class :extends javafx.application.Application))
(def app (atom nil))
(defn -start [this stage]
(let [vbox (VBox.)
scene (Scene. vbox 200 200)]
(reset! app this)
(.add (.getChildren vbox) (Label. "Hello World"))
(doto stage
(.setTitle "Hello From Clojure!")
(.setScene scene)
(.show))))
(defn -main [& args]
(Application/launch myapp.core (into-array String [])))
Note that there's a wrapper over JavaFX called Cljfx, which would allow you to -among other things- test your project in REPL, without creating any uberjars.
Minimal example:
Dependency: [cljfx "1.7.21"]
Core:
(ns myapp.core
(:require [cljfx.api :as fx])
(:gen-class))
(fx/on-fx-thread
(fx/create-component
{:fx/type :stage
:showing true
:title "Cljfx example"
:width 300
:height 100
:scene {:fx/type :scene
:root {:fx/type :v-box
:alignment :center
:children [{:fx/type :label
:text "Hello world"}]}}}))