11

Clojureを学び始め、JavaFXforGUIを試してみたいと思います。私はこの記事を見つけました:http://nailthatbug.ne ​​t/2011/06/clojure-javafx-2-0-simple-app/ですが、迅速なテストと利便性のためにreplを介して開始したいと思います。

したがって、たとえば、これをreplで記述して、新しいウィンドウを表示できます。

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

javafx.application.Applicationでそのようなことを行う方法はありますか?新しいJavaFXウィンドウを表示しますか?

どうも。アンドリュー。

4

3 に答える 3

10

JavaFX アプリケーション クラスのドキュメントを読むと、アプリケーション クラスが抽象クラスであり、直接インスタンス化できないことがわかります。つまり、少なくとも 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 をセットアップする手順に従ってください。

于 2012-08-17T17:22:16.260 に答える
8

まだ初期段階ですが、 Upshotを使用して REPL から JavaFx を使用することができました。Application主なトリックは、シーンを完全に無視して直接作成することです。これを行うには、ランタイムを強制的に初期化するだけでよく、その例はcore.clj:69で確認できます。もう 1 つの秘訣は、JavaFX スレッドで確実に実行するために、行うことのほとんどすべてをrun-nowブロックにラップする必要があることです。JavaFX は、Swing よりもスレッド化に関してはるかにうるさいです。

于 2012-08-22T04:14:47.630 に答える
3

たくさんのデイブ。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)
                                            )))))))))))

JavaFX2.2が必要です。そしてこの前に、REPLで:(Platform / setImplicitExit false)これはこのコードの直接の移植です:JavaFXをSwingアプリケーションに統合する ので、非常に必須で素朴に見えます、Clojureの世界ではcoz Im noob、そしてもっと経験豊富な人かもしれません、これを書き直してくださいもっとClojureishの方法で。とにかく、今はうまくいきます。2つのランチャーの概念について考えます。1つは(launch-javafx)を介したreplベースの開発用で、もう1つは通常のjavafx.application.Applicationランチャーを介した公開用です。それらが互いに同等であるかどうかはまだわかりません(つまり、javafx.embed.swing.JFXPanelの場合は完全なJavaFX APIを使用できます)。そうであれば、これは私の目標(REPLによる開発)に適しています。そして、ImはまだUpshotコードを調査しています-もっと穏やかなweyが見つかるかもしれません。

于 2012-08-24T01:20:17.803 に答える