Swing,JavaFX和Clojure对类路径不起作用

时间:2016-05-09 15:36:47

标签: swing javafx clojure

也许这是Clojure中的错误...我的问题是......

为什么当我在下面的代码中创建一个新的JLabel时,在创建JavaFX Stage时会得到ClassNotFoundException但是当我不创建JLabel时,就会创建JavaFX Stage(并且找到类) ?

要重现这个,请使用lein new app class-path-fail创建一个新的leiningen项目,并将core.clj替换为此代码:

(ns class-path-fail.core
  (:gen-class)
  (:import (javafx.stage Stage)
           (javafx.application Platform)
           (javax.swing JLabel SwingUtilities)
           (javafx.embed.swing JFXPanel)))

(JFXPanel.)

(SwingUtilities/invokeAndWait #(new JLabel "ha"))
(defn simple-fn-will-fail []
  (let [form `(fn [] (new Stage))]
    (eval form)))
(Platform/runLater #(simple-fn-will-fail))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

你可以通过运行来验证这不起作用......但是......注释掉JLabel的创建并观察它是否有效!!

我使用的是Clojure 1.8.0。

这是我的project.clj:

(defproject class-path-fail "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :main ^:skip-aot class-path-fail.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

我发现如果前两行代码被反转,那么在类路径上找到Stage并加载。新的前两行看起来像:

(SwingUtilities/invokeAndWait #(new JLabel "ha"))
(JFXPanel.)

1 个答案:

答案 0 :(得分:-1)

我遇到了类似的问题(虽然在不同的上下文中),我怀疑它是由JavaFX应用程序线程的类加载器配置引起的,不一定是Clojure特有的。例如,请参阅此类似问题:API works with Java application but not JavaFX和:https://community.oracle.com/thread/2564617?start=0&tstart=0

那就是说,你为什么要使用这么多级别的间接,以及如此多的不同机制来安排将来发生的事情?正常的Clojure代码中很少需要eval函数。

可以简化行(Platform/runLater #(simple-fn-will-fail)):不需要匿名函数,因为simple-fn-will-fail已经是一个不带参数的函数。所以这一行完全等效(并且以完全相同的方式失败):(Platform/runLater simple-fn-will-fail)

此外,simple-fn-will-fail实际上并没有尝试创建一个新的Stage,它只返回一个将执行该操作的函数(并且该函数被丢弃,从不被调用),所以如果你没有调用通过调用eval编译器,不会发生这个问题。

如果我们可以退后一步,更好地了解您实际要完成的工作,可能有办法解决JavaFX应用程序线程上的类加载器问题。

无论如何,这些都是一些想法。也许我们会从更深入了解JavaFX和Clojure编译的人那里听到更多信息。

我在下面发表评论后发现了更多,并发现即使我在-main中删除了副作用形式,也会抛出同样的异常,试图评估{{1}中的表单}。因此,JavaFX类加载器更加强烈地指出了这个问题。

然而,通过确保在正常的Clojure线程上进行编译,然后使用{运行生成的函数(我认为,这可能是您想要做的),我能够让一切运行正常。 {1}}。这是我的调整版本:

simple-fn-will-fail

使用此版本,我可以毫无问题地调用Platform/runLater