簡體   English   中英

Clojure repl的JavaFX

[英]JavaFX from Clojure repl

我開始學習Clojure,並且想嘗試JavaFX for GUI。 我找到了這篇文章: http : //nailthatbug.ne​​t/2011/06/clojure-javafx-2-0-simple-app/ ,但是我想通過repl來啟動它,以進行快速測試和方便。

因此,例如,我可以這樣編寫並查看新窗口:

(defn main-start []
  (doto (JFrame. "Window!")
   (.setSize (java.awt.Dimension. 400 300))
   (.setVisible true)))

有什么辦法用javafx.application.Application做這樣的事情-看到新的JavaFX窗口嗎?

謝謝。 安德魯。

如果閱讀JavaFX Application類文檔 ,您將看到Application類是一個抽象類,不能直接實例化。 這意味着,您至少必須創建javafx.application.Application的子類。

生命周期

JavaFX應用程序的入口點是Application類。 每當啟動應用程序時,JavaFX運行時都會依次執行以下操作:

  1. 構造指定的Application類的實例
  2. 調用init()方法
  3. 調用start(javafx.stage.Stage)方法
  4. 等待應用程序完成,這發生在以下情況之一:應用程序調用Platform.exit()時,最后一個窗口已關閉並且Platform上的implicitExit屬性為true調用stop()方法注意,start方法為抽象,必須重寫。

因此,您需要使用gen-class宏(在博客文章中可以看到)生成一個類,該類具有一個start方法才能啟動該應用程序。

編輯:使用添加的gen-class方法鏈接到示例應用程序
在Clojure中創建了一個帶有簡單示例JavaFX應用程序Github存儲庫 這是遵循gen-class方法的Clojure文件:

(ns jfx.app
  (:import (javafx.beans.value ChangeListener ObservableValue)
           (javafx.concurrent Worker$State)
           (javafx.event ActionEvent EventHandler)
           (javafx.scene Scene)
           (javafx.scene.control Button)
           (javafx.scene.layout StackPane)           
           (javafx.stage Stage)
           (javafx.scene.web WebView)))

(gen-class
 :name clj.jfx.App
 :extends javafx.application.Application
 :prefix "app-") 

(defn app-start [app ^Stage stage]
  (let [root (StackPane.)
        btn (Button.)
        web-view (WebView.)
        state-prop (.stateProperty (.getLoadWorker (.getEngine web-view)))
        url "http://clojure.org"]

    ;; Add a WebView (headless browser)
    (.add (.getChildren root) web-view)
    ;; Register listener for WebView state changes
    (.addListener state-prop
                  (proxy [ChangeListener] []
                    (changed [^ObservableValue ov
                              ^Worker$State old-state
                              ^Worker$State new-state]
                      (println (str "Current state:" (.name new-state)))
                      (if (= new-state Worker$State/SUCCEEDED)
                        (println (str "URL '" url "' load completed!"))))))
    ;; Load a URL
    (.load (.getEngine web-view) url)

    ;; add a Button with a click handler class floating on top of the WebView
    (.setTitle stage "JavaFX app with Clojure")
    (.setText btn "Just a button")
    (.setOnAction btn
                  (proxy [EventHandler] []
                    (handle [^ActionEvent event]
                      (println "The button was clicked"))))
    (.add (.getChildren root) btn)

    ;; Set scene and show stage
    (.setScene stage (Scene. root 800 600))
    (.show stage)))

(defn app-stop
  "Stop method is called when the application exits."
  [app]
  (println "Exiting application!")
  )

(defn launch
  "Launch a JavaFX Application using class clj.jfx.App"
  []
  (javafx.application.Application/launch clj.jfx.App (into-array String [])))

必須編譯jfx.app命名空間才能啟動應用程序,如果直接在REPL中運行代碼,則該命名空間將無法工作。 如果要嘗試使用代碼,請按照說明在項目的README.md文件中使用Maven和Leiningen設置JavaFX。

盡管它仍處於起步階段,但我已經能夠使用Upshot從REPL中使用JavaFx。 主要技巧是完全忽略Application並直接創建場景。 為此,您只需要強制運行時進行初始化即可,其示例可以在core.clj:69上看到。 另一個技巧是,幾乎所有操作都必須包裝在“立即run-now塊中,以確保其在JavaFX線程上運行。 與Swing相比,JavaFX對線程的選擇更為挑剔。

非常感謝戴夫。 我還找到了javafx.embed.swing.JFXPanel的解決方案:

(ns to-dell3 
  (:import 
    (javafx.application Application Platform)
    (java.util Date)
    (javafx.scene Group Scene)
    (javafx.scene.text Font Text)
    (javax.swing JFrame SwingUtilities)
    ChartApp1
    javafx.scene.paint.Color
    javafx.embed.swing.JFXPanel))



(defn launch-javafx [] (SwingUtilities/invokeLater 
  (proxy [Runnable] [] (run [] 
                (let [frame2 (JFrame. "JFrame")
                      fxPanel2 (JFXPanel.)
                      ]
                  (do 
                    (.setSize frame2 500 200 )
                    (.setVisible frame2 true)
                    (.setDefaultCloseOperation frame2 JFrame/DISPOSE_ON_CLOSE)
                    (.add frame2 fxPanel2)
                    (Platform/runLater (proxy [Runnable] [] (run [] (let [root2 (Group.)
                                              scene2 (Scene. root2  Color/ALICEBLUE)
                                              text2 (Text.)]
                                          (do
                                            (.setX text2 40)
                                            (.setY text2 100)
                                            (.setFont text2 (Font. 25))
                                            (.setText text2 "Welcome to Clojure + REPL + JavaFX!")
                                            (.add (.getChildren root2) text2)
                                            (.setScene fxPanel2 scene2)
                                            )))))))))))

需要JavaFX 2.2。 而且在REPL中,這是這樣的:(Platform / setImplicitExit false)這是此代碼的直接端口: 將JavaFX集成到Swing應用程序中,因此它看起來非常必要和幼稚,因為在Clojure世界中,我可能是個經驗豐富的人,請重寫此代碼以更多Clojureish的方式。 無論如何,它現在對我有用,我考慮了兩個啟動器的概念:一個通過(launch-javafx)用於基於repl的開發,一個用於發布:通過普通的javafx.application.Application啟動器。 我仍然不知道它們是否彼此等效(我的意思是在javafx.embed.swing.JFXPanel情況下可以使用完整的JavaFX API),如果可以的話,這很適合我的目標(通過REPL開發)。 而且我仍在調查Upshot代碼-也許會發現它更溫和。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM