2012-08-17 7 views
10

私はClojureを学び始めます.GUI用にJavaFXを試してみたいと思います。私はこの記事を見つけました:http://nailthatbug.net/2011/06/clojure-javafx-2-0-simple-app/ ですが、私は迅速なテストと利便性のためにreplを使って起動したいと思います。JavaFX from Clojure repl

ので、例えば、私はREPLでこれを書いて、新しいウィンドウを表示することができます

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

はjavafx.application.Applicationで、このようなことを行うための任意の方法がある - 新しいJavaFXのウィンドウを参照するには?

Thx。アンドリュー。

+0

あなたはどのようにしてreplを起動しますか? JavaFXランタイム依存関係のため、jfxrt.jarはクラスパス上になければなりません。 Leiningenを使用してプロジェクトを作成しましたか? –

答えて

8

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

9

JavaFX Application class documentationを読むと、Applicationクラスが抽象クラスであり、直接インスタンス化できないことがわかります。つまり、少なくともjavafx.application.Applicationのサブクラスを作成する必要があります。

ライフサイクル

JavaFXアプリケーションのエントリポイントは、Applicationクラスです。 のJavaFXランタイムはアプリケーション が起動されるたびに、順番に、次の処理を行います。

  1. がスタート(JavaFXのコールのinit()メソッドを呼び出し、指定Applicationクラス
  2. のインスタンスを構築します。 stage.Stage)メソッド
  3. のいずれかが発生したときにアプリケーションが終了するのを待機します。最後のウィンドウが終了したPlatform.exit()が呼び出されました が閉じられ、PlatformのimplicitExit属性がtrueです。 stop()メソッドstartメソッドは抽象メソッドであり、 をオーバーライドする必要があることに注意してください。

したがって、あなたは、クラスを生成する必要がある - それはブログ記事に見られるようにGEN-クラスのマクロを使用して - startメソッドを使用してアプリケーションを起動できるようにします。

編集:gen-classアプローチを使用したサンプルアプリケーションへのリンク
私はGithub repository with a simple example JavaFX application in Clojureを作成しました。ここではClojureのファイルがGEN-クラスのアプローチ以下の通りです:

(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でコードを実行する場合、これは動作しません、アプリケーションを起動するためにコンパイルする必要があります。コードを試したい場合は、project's README.md fileにMavenとLeiningenを使用してJavaFXを設定する手順に従ってください。

+0

これは、replからJavaFXアプリを起動する方法がないことを意味します。 – Andrew

+0

私はあなたがアプリケーションから継承し、そのオブジェクトを使用するクラスを作成するために 'proxy'を使うことができると思います。 – Ankur

+1

私はプロキシクラスで試してみましたが、うまくいきませんでした。私が行った小さなテストでは、クラスコンストラクタが終了する前に抽象メソッドが呼び出されたときに、プロキシされたメソッドは早期にClojureによって提供されないことを確認しました。つまり、gen-classが唯一の選択肢です。 –

2

Thx a lot Dave。 javafx.embed.swingのソリューションも見つかりました。JFXパネル:

(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で(プラットフォーム/ setImplicitExit false) これはこのコードの直接ポートです:Integrating JavaFX into Swing Applications これはClojureの世界では非常に不可欠で、素朴な、coz Im noobのように見えます。 Clojureish方法。とにかく、それは今私のために働く、私は2つのランチャーのコンセプトについて考える:1つはrepl-based development(launch-javafx)用で、もう1つはpublish:普通のjavafx.application.Applicationランチャーを通して。私はまだそれらが互いに同等であるかどうかわかりません(javafx.embed.swing.JFXPanelの場合は完全なJavaFX APIを利用できます)、もしそうなら、これは私の目標(REPLによる開発)に合っています。そして、まだアップショットのコードを調べている - もっと穏やかに見えるかもしれない。

関連する問題