在之前實現的Controller中,不管是fields還是methods,都直接使用了public。一方面是為了讓FMLLoader能夠正確查找並注入,另一方面是為了避開使用@FXML。
但這樣做並不是通常性的作法,正常仍會有field或是method需要是私有(private)的情況。不過直接改成私有會讓FXMLLoader無法注入,因此需要加上@FXML這個Annotation:
@FXMLpackage CalcFX;
import javafx.fxml.FXML; // 引入 javafx.fxml.FXML
public class CalcFXController {
@FXML // 將display標注@FXML,讓FXMLLoader再反射時可以查找到
private TextField display;
private final Interpreter interpreter;
private final Function buttonPressFunction;
@FXML // 將handleButtonClick()標注@FXML,讓FXMLLoader再反射時可以查找到
private void handleButtonClick(ActionEvent event) {
Button target = (Button) event.getTarget();
String label = target.getText();
SimpleString lispLabel = new SimpleString(label);
JavaObject lispDisplay = new JavaObject(display);
buttonPressFunction.execute(lispLabel, lispDisplay);
}
}
透過引入和使用javafx.fxml.FXML標注display與handleButtonClick(),即使兩者是私有的,也不會讓FXMLLoader查找不到,能夠順利注入元件和綁定事件處理。
ABCL實現的運行時動態類別,方法同樣可以設成私有和使用@FXML註明:
(define-symbol-macro *calculator-controller-class*
(java:jnew-runtime-class
"CalculatorController"
:fields '(("display" "javafx.scene.control.TextField"))
;; 定義方法:對應 Scene Builder 的 On Action
:methods `(("handleButtonClick"
:void ("javafx.event.ActionEvent")
(lambda (this event)
(let* ((target (#"getTarget" event))
(label (#"getText" target))
(display (jfield "display" this)))
(handle-button-press label display)))
:modifiers ("private") ;; 私有方法
:annotations ("javafx.fxml.FXML"))))) ;; 使用 @FML
不過我嘗試將field display同樣設定,並無法發揮效果。在ABCL只能有限度的完成,不過ABCL的運行時動態類別的私有設定好像本來意義就不是太大。
public 能跑,但更多時候使用私有封裝才是更常見的作法private需要搭配@FXML,FXMLLoader才查找的到