2017-03-24 10 views
0

私はエディタで使用されるフォントを選択できるオプション・ダイアログを含むClojureプログラムを構築しています。ちょうど他の多くのプログラムと同様に、ドロップダウンリストにフォント名をフォントで表示するComboBoxをユーザに提示したいと思います(例えば、 'Calibri'はCalibriフォントで表示され、 'Arial'はArialで表示されますon)。ClojureのJavaFXフォント・フェイス・ダイアログ

以前はJavaで、セルファクトリを使用してリスト内の各セルの外観をカスタマイズしました。

Clojureへの翻訳は機能しません。ここで

は、私がこれまでに出ているものです:

(defn build-font-list-cell 
"Return a Cell with an overridden updateItem implementation for 
the cells in the font list combo. Format the name of the font in 
the actual font." 
[] 
(proxy [TextFieldListCell] [] 
    (updateItem [^String family mt] 
    (proxy-super updateItem family mt) 
    (if mt 
     (.setText this nil) 
     (do 
     (.setFont this (Font/font family)) 
     (.setText this family)))))) 

(defn build-font-list-cell-factory 
    [] 
    (proxy [Callback] [] 
    (call [list-view] 
     (build-font-list-cell)))) 

(defn build-font-face-combo 
    "Build, configure, and return the combo box used to select the font 
    face for the editor." 
    [] 
    (let [family-list (FXCollections/observableArrayList (Font/getFamilies)) 
    font-face-combo (ComboBox. family-list) 
    current-face @tentative-font-face] 

    (.setEditable font-face-combo true) 
    (.addListener (.selectedItemProperty (.getSelectionModel font-face-combo)) 
        ^ChangeListener (face-combo-listener font-face-combo)) 
    (.setCellFactory font-face-combo (build-font-list-cell-factory)) 
    (select-item-in-combo font-face-combo current-face) 
    font-face-combo)) 

コンパイラがproxyの宣言でbuild-font-list-cell機能で、この上ExceptionInInitializerErrorをスローします。 IDE(IntelliJ)は、 'super-proxy`への呼び出しで、updateItem引数に関する警告を表示し、解決できないことを示します。上記の行の上書きについて不平を言っていないので、なぜ私は理解できません。

これは前に働いていたJavaコードの比較的単純な翻訳のようですが、私は明らかに何かが欠落しています。それともこれが正しいアプローチですか?

EDIT:次のMCVEを追加してください。これはコンパイルされ、表示されているように動作しますが、もちろんフォントのフォント名はフォーマットされません。リスト内のコードのコメントを解除してセルファクトリを作成しようとすると、コンパイラが目にするものが生成されます。

(ns ffcbd.core 
    (:gen-class 
    :extends javafx.application.Application) 
    (:import (javafx.application Application) 
      (javafx.collections FXCollections) 
      (javafx.scene.control ComboBox) 
      (javafx.scene.control.cell TextFieldListCell) 
      (javafx.scene.text Font) 
      (javafx.scene.layout BorderPane) 
      (javafx.scene Scene) 
      (javafx.stage Stage) 
      (javafx.util Callback))) 

;(defn build-font-list-cell [] 
; (proxy [TextFieldListCell] [] 
; (updateItem [family mt] 
;  (proxy-super updateItem family mt) 
;  (if mt 
;  (.setText this nil) 
;  (do 
;   (.setFont this (Font/font family)) 
;   (.setText this family)))))) 

;(defn build-font-list-cell-factory [] 
; (proxy [Callback] [] 
; (call [list-view] 
;  (build-font-list-cell)))) 

(defn build-font-face-combo [] 
    (let [family-list (FXCollections/observableArrayList (Font/getFamilies)) 
     font-face-combo (ComboBox. family-list)] 

; (.setCellFactory font-face-combo (build-font-list-cell-factory)) 
    (.select (.getSelectionModel font-face-combo) 0) 
    font-face-combo)) 

(defn -start [this stage] 
    (let [root (BorderPane.) 
     scene (Scene. root)] 

    (.setTop root (build-font-face-combo)) 
    (.add (.getChildren root) (build-font-face-combo)) 
    (.setMinSize root 300 275) 

    (doto stage 
     (.setScene scene) 
     (.setTitle "Font Face ComboBox Demo") 
     (.show)))) 

(defn -main [& args] 
    (Application/launch ffcbd.core args)) 

Javaのバージョンからのもう1つの違いは、JavaのリストセルがListCellであるということです。しかし、super.updateItemに電話する必要があります。私がドキュメントを理解しているので、proxyは、メソッドがpublicでない限り、superを呼び出すことはできません。 protectedListCellですが、publicTextFieldListCellです。

EDIT#2:ここでは、Javaで動作するコードの例を示します。

package FontFaceDialog; 

import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 
import javafx.scene.control.ComboBox; 
import javafx.util.Callback; 

public class Main extends Application { 

    private ComboBox<String> buildFontFaceCombo() { 
     ObservableList<String> lst = FXCollections.observableList(javafx.scene.text.Font.getFamilies()); 
     ComboBox<String> cb = new ComboBox<String>(lst); 
     cb.getSelectionModel().select(0); 
     cb.setCellFactory((new Callback<ListView<String>, ListCell<String>>() { 
      @Override 
      public ListCell<String> call(ListView<String> listview) { 
       return new ListCell<String>() { 
        @Override 
        protected void updateItem(String family, boolean empty) { 
         super.updateItem(family, empty); 
         if (empty) { 
          setText(null); 
         } else { 
          setFont(Font.font(family)); 
          setText(family); 
         } 
        } 
       }; 
      } 
     })); 
     return cb; 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     BorderPane root = new BorderPane(); 
     root.setTop(buildFontFaceCombo()); 
     primaryStage.setTitle("Font Face Dialog Example"); 
     primaryStage.setScene(new Scene(root, 300, 275)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

私は ';'の壁は不要であることを指摘したいと思います。フォームの前に置かれた "コメントマクロ"##を使って、フォーム全体をコメントアウトすることができます。 – Carcigenicate

+0

@Carcigenicate:うわー!それは知らなかった。私はちょうどブロックのコードをコメントアウトするためにIDEコマンドを使用しました。とてもかっこいい。 – clartaq

+0

Ya。テストのために関数全体をコメントアウトするのに便利です。 – Carcigenicate

答えて

0

Clojureにはthisはありません。私はそれがエラーの核心だと思う。

メソッドのシグネチャは、Iも不要^Stringヒントを削除することをお勧め

public void updateItem(T item, boolean empty) 

あります。あなたがまだそれを見ていない場合は、there are some examples on ClojureDocs.org

+0

問題の一部である 'this 'については正しいかもしれませんが、' this'はClojureに存在します。あなたが指し示したドキュメント(と他者)が言うように、それは 'proxy'に対して暗黙的ですが、' reify'についても明白です。私はそれらをIDEのエラーフラグを排除するために配置します。それらを削除しても効果はありません - まだ例外がスローされます。関数の後半で反射警告を除去するために、 '^ String'ヒントを入れました。質問にいくつかの文脈を追加し、簡単なMCVEをまとめようとします。 – clartaq

0

残念ながら、私はこれまでClojureでこれを行う方法を理解することができませんでした。私はこの作業をする必要があるので、私は別の方法を使用しています。私はJavaでそれを行う方法を知っているので、なぜJavaで謎のビットをしないのですか?それは審美的に満足できるものではありませんが、機能します。

leinで多言語プログラムを使用することは可能ですが、一見したことです。

まず、デモのClojureの部分を示します。

ns ffcbd.core 
    (:gen-class 
    :extends javafx.application.Application) 
    (:import (com.example FontFaceListCell) 
      (javafx.application Application) 
      (javafx.collections FXCollections) 
      (javafx.scene.control ComboBox) 
      (javafx.scene.text Font) 
      (javafx.scene.layout BorderPane) 
      (javafx.scene Scene) 
      (javafx.stage Stage) 
      (javafx.util Callback))) 

(defn build-font-list-cell-factory [] 
    (proxy [Callback] [] 
    (call [list-view] 
     (FontFaceListCell.)))) 

(defn build-font-face-combo [] 
    (let [family-list (FXCollections/observableArrayList (Font/getFamilies)) 
     font-face-combo (ComboBox. family-list)] 
    (.setCellFactory font-face-combo (build-font-list-cell-factory)) 
    (.select (.getSelectionModel font-face-combo) 0) 
    font-face-combo)) 

(defn -start [this stage] 
    (let [root (BorderPane.) 
     scene (Scene. root)] 

    (.setTop root (build-font-face-combo)) 
    (.add (.getChildren root) (build-font-face-combo)) 
    (.setMinSize root 400 275) 

    (doto stage 
     (.setScene scene) 
     (.setTitle "Font Face ComboBox Demo") 
     (.show)))) 

(defn -main [& args] 
    (Application/launch ffcbd.core args)) 

上部にはcom.example.FontFaceListCellのインポートがあることに注意してください。それがJavaの部分です。その小さなクラスのリストがあります。

package com.example; 

import javafx.scene.control.ListCell; 
import javafx.scene.text.Font; 

public class FontFaceListCell extends ListCell<String> { 
    @Override 
    public void updateItem(String item, boolean empty) { 
     super.updateItem(item, empty); 
     if (empty) { 
      setText(null); 
     } else { 
      setFont(Font.font(item, 16.0d)); 
      setText(item); 
     } 
    } 
} 

このクラスはListCellを拡張しupdateItemメソッドをオーバーライド。プログラムを実行してComboBoxをクリックすると、私のシステム上でこのようなことが起こります。

leinでこの作業を取得するために、前述したように、あなたはいくつかのより多くの手間のかかるビットを必要とします。

Javaコードをコンパイルするには、leinはJavaがどこにあるかを知る必要があります。この行を私のグローバルプロファイルに追加しました。

:java-cmd "C:\\Program Files\\Java\\jdk1.8.0_121\\bin\\java.exe" 

今、私はWindowsとLinux上で同じprofiles.cljのファイルを使用することはできませんので、これはちょっと吸います。

これを動作させるには、project.cljを少し変更して、leinにJavaコードの場所とコンパイラに渡すオプションを教えてください。ここで私が使ったことがあります。

(defproject ffcbd "0.1.0-SNAPSHOT" 
    :description "A demo of a styled font selection ComboBox in Clojure." 
    :dependencies [[org.clojure/clojure "1.8.0"]] 
    :java-source-paths ["java"] 
    :javac-options  ["-target" "1.8" "-source" "1.8"] 
    :aot :all 
    :main ffcbd.core) 

私が興味を持つ人のためのIntelliJ IDEAプロジェクトを含むのBitbucket上のMercurial repoを設置しました。

Clojureを使用しているだけで、このすべてを稼働させるのはまだ素晴らしいことです。私は確信しているgen-classそれを行うだろうが、まだそれを考え出していない。

関連する問題