Clojure JavaFX 实时操作

Clojure JavaFX Live Manipulation

我创建了一个简单的“Hello, World!”使用 JavaFX 的 Clojure 应用程序。

有很多类似的,但这一个是我的,就像步枪手的信条一样。此外,这个适用于最新的 JavaFX,并且不使用 Swing JFX 面板:

(ns ezclj.core
  (:gen-class :extends javafx.application.Application)
  (:import (javafx.application Application)
           (javafx.fxml FXMLLoader)
           (javafx.scene Scene Group)))

(def _app (atom nil))

(defn -start [app stage]
  (reset! _app app)
  (.setTitle stage "Hello From Clojure!")
  (let [f (Scene. (FXMLLoader/load (.getResource (.getClass app) "sample.fxml")) 800 600)
        _ (.setScene stage f)])
  (.show stage)
  (println "Running but doesn't return to REPL"))


(defn -main
  [& args]
  (Application/launch ezclj.core (into-array String [])))

如果我在 REPL 中启动它并使用 (-main) 启动它,则会出现 window。我的第一个问题是为什么这样做有效?正在启动 Leiningen 编译 ezclj.core class?如果没有,Application/launch 怎么能找到所说的 class?

现在,这会显示 sample.fxml 中的任何内容并继续其愉快的方式...这很好...但是挂断了 REPL...这很糟糕。但是,如果我创建一个线程:

(def t (Thread. (fn[] (-main))))
(.start t)

REPL 可用,我可以直接访问 _app,这引出了我的第二个问题:我现在可以通过 _app 更改 JFX 图来安全地构建我的 UI 吗?还是我忽略了一些东西,比如 JFX 线程上的潜在冲突?

我没有玩过 JavaFX,但从你的问题中可以清楚地看出 Application/launch 正在阻塞主线程。因此,正如您所发现的那样,在另一个线程中启动它就是答案。一个更简单的方法是使用:

(defn -main
  [& args]
  (future 
    (Application/launch ezclj.core (into-array String []))))

因为 future 获取表达式主体并在另一个线程中调用它们。

请查看 this list of documentation,尤其是 Clojure CheatSheet。

尽情享受吧!


P.S.

一旦掌握了基础知识,您可能会发现 lein-test-refresh 插件的“自动重新加载”工作流程很有用。

如果您遵循 this template project 中的模式,lein-test-refresh 插件将在每次保存文件后重新加载并重新编译您的代码。 您可以从单元测试中调用 -main,这样它会在每次保存文件后 运行。