似乎在F
XML中如果不指定ID(CSS),则默认使用fx:id值.我之前的理解是两个完全不相交,ID为CSS而且只有CSS. fx:控制器中@FXML绑定的id.
这可以通过一个小测试来证明 – 三个按钮,首先是ID,第二个是FX:ID,第三个是两种类型的ID.
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <children> <Button id="cssid0" mnemonicParsing="false" text="Button" /> <Button fx:id="fxid1" mnemonicParsing="false" text="Button" /> <Button id="cssid2" fx:id="fxid2" mnemonicParsing="false" text="Button" /> </children> </VBox>
使用Node.lookup(cssSelector)允许通过fx:id进行选择
@Override public void start(Stage stage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("/foo.fxml")); Parent p = loader.load(); System.out.println(p.lookup("#cssid0")); // => Button[id=cssid0,styleClass=button]'Button' System.out.println(p.lookup("#fxid1")); // => Button[id=fxid1,styleClass=button]'Button' System.out.println(p.lookup("#fxid2")); // => null (if there is a CSS ID it takes precedent) System.out.println(p.lookup("#cssid2")); // Button[id=cssid2,styleClass=button]'Button' stage.setScene(new Scene(p,200,200)); stage.getScene().getStylesheets().add("/foo.css"); stage.show(); }
CSS也允许通过fx:ID进行选择
#cssid0 { -fx-color: red; } #fxid1 { -fx-color: green; } #cssid2 { -fx-color: blue; }
现在问题What’s the difference between fx:id and id: in JavaFX?,Javadoc for Node.getId()或我能找到的任何其他地方似乎都没有涵盖这一点.
这个功能非常有用,因为我们只需要指定一个fx:id,它可以用于控制器,CSS和使用test-FX的单元测试.
是否可以使用这种方法,或者我是否对未记录的行为进行假设,这些行为可能会在以后的版本中发生变化?或者它是否记录在某个我遗漏的地方?
解决方法
IMO在
Introduction to FXML :: Variable Resolution中有部分记录.但初看起来并不那么明显:
Assigning an fx:id value to an element creates a variable in the
document’s namespace that can later be referred to by variable
dereference attributes …
Additionally,if the object’s type defines
an “id” property,this value will also be passed to the objects
setId() method.
它应该用“if object定义idProperty并且尚未设置…”来完成.基于相关源代码的是FXMLLoader在708左右:
// Add the value to the namespace if (fx_id != null) { namespace.put(fx_id,value); // If the value defines an ID property,set it IDProperty idProperty = value.getClass().getAnnotation(IDProperty.class); if (idProperty != null) { Map<String,Object> properties = getProperties(); // set fx:id property value to Node.id only if Node.id was not // already set when processing start element attributes if (properties.get(idProperty.value()) == null) { properties.put(idProperty.value(),fx_id); } } ... }
我认为建立这种行为是可以的.