【发布时间】:2017-03-24 15:01:14
【问题描述】:
我正在构建一个 Clojure 程序,其中包含一个选项对话框,用户可以在其中选择编辑器中使用的字体。就像许多其他程序一样,我想向用户展示一个 ComboBox,其中下拉列表显示字体本身的字体名称(例如,“Calibri”以 Calibri 字体显示,“Arial”以 Arial 显示,等等开。)
过去在 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) 在对“超级代理”的调用中显示有关 updateItem 参数的警告,表示无法解决。我不明白为什么不这样做,因为它没有抱怨上面一行的覆盖。
这似乎是对以前有效的 Java 代码的相对简单的翻译,但我显然遗漏了一些东西。或者这甚至是正确的方法吗?
编辑:添加以下 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 版本的另一个区别是Java 中的列表单元格是ListCell。但我需要打电话给super.updateItem。据我了解文档,proxy 不允许您调用 super,除非方法是 public。在ListCell 中是protected,但在TextFieldListCell 中是public。
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);
}
}
【问题讨论】:
-
我想指出
;的那堵墙是不必要的。您可以使用将“注释宏”#_放置在表单之前来注释掉整个表单。 -
@Carcigenicate:哇!我不知道。我只是用IDE命令注释掉了一段代码。很酷。
-
是的。用于注释掉整个测试函数。