我有一个定义如下的自定义控件:
<fx:root type="javafx.scene.Group" xmlns:fx="http://javafx.com/fxml" fx:controller="com.theCorp.theTool.controllers.LimitsController">
<Group id="Group" layoutX="0.0" layoutY="0.0">
<children>
<Group id="Count" layoutX="0.0" layoutY="20.0">
<children>
<Label layoutX="0.0" layoutY="3.0" prefWidth="59.0" text="Count" />
<TextField id="Count.Min" fx:id="countMin" layoutX="59.0" layoutY="0.0" prefWidth="132.0" promptText="Min" />
<TextField id="Count.Max" fx:id="countMax" layoutX="191.0" layoutY="0.0" prefWidth="132.0" promptText="Max" />
</children>
</Group>
<Button id="SaveButton" fx:id="saveButton" layoutX="12.0" layoutY="85.0" mnemonicParsing="false" onAction="#save" text="Save" />
</children>
</Group>
</fx:root>
我有一个 Control
类,它以通常的方式加载它:
public class LimitsControl extends Group {
private static final String fxmlFileName = "Limits.fxml";
public LimitsControl() {
super();
URL fxml = getClass().getResource(fxmlFileName);
if (fxml == null) {
fxml = getClass().getResource("/fxml/" + fxmlFileName);
}
// Create the loader.
FXMLLoader loader = new FXMLLoader(fxml);
loader.setRoot(this);
try {
// Load the fxml.
loader.load();
// Pull back the controller.
LimitsController controller = loader.getController();
// Tell it about me.
controller.setControl(this);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
我有一个 Controller
类,看起来有点像这样:
public class LimitsController implements Initializable {
// Control.
private LimitsControl control;
@FXML
private TextField countMin;
@FXML
private TextField countMax;
@FXML
private Button saveButton;
/**
* Initializes the controller class.
*
* @param url
* @param rb
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
log.info("Loading: " + url + " rb=" + rb+" control="+control);
// Make the save button call my save.
saveButton.setOnAction((ActionEvent e) -> {
save(e);
});
}
public void setControl(LimitsControl control) {
log.info("Control="+control);
this.control = control;
}
@FXML
private void save(ActionEvent event) {
// What is the ID of me?
Parent myGroup = saveButton.getParent();
// Pull the id of the control that enclosed my group.
String myId = myGroup.getParent().getId();
log.info("Saving: " + myId);
}
}
我将这些控件插入场景中的多个位置,每次都使用不同的 id
,如下所示:
<TitledPane fx:id="Today" animated="false" text="Today">
<tooltip>
<Tooltip text="Parameters will only be used for today." />
</tooltip>
<content>
<LimitsControl id="Today.Limits" />
</content>
</TitledPane>
我的问题是,这些控件必须由需要控件的 id
的数据填充,但当 Controller 初始化时,它没有父级。
按下保存按钮时,id
可用 - 请参阅 save
方法爬上父树以收集控件的 id。遗憾的是父级在初始化时为空。
当父 ID 可用时,如何正确初始化字段?或者我做错了,有一个正确的
方法?
最佳答案
首先,注入(inject)控件,而不是使用设置方法耦合所有内容:
<fx:root type="javafx.scene.Group" xmlns:fx="http://javafx.com/fxml" fx:controller="com.theCorp.theTool.controllers.LimitsController" fx:id="control">
和
// Control.
@FXML
private LimitsControl control;
如果我理解正确的话,您尝试获取的 id 是 LimitsControl 本身的 id。要使其“尽早”可用,请在 LimitsControl 的构造函数中定义一个参数并在那里设置 id:
public LimitsControl(String id) {
super();
setId(id);
// code as before...
}
现在,因为您不再有默认构造函数,所以您需要为 LimitsControl 创建一个构建器:
public class LimitsControlBuilder {
private String id ;
private LimitsControlBuilder() {
this.id = "" ;
}
public static LimitsControlBuilder create() {
return new LimitsControlBuilder();
}
public LimitsControlBuilder id(String id) {
this.id = id ;
return this ;
}
public LimitsControl build() {
return new LimitsControl(id);
}
}
现在你可以做
<LimitsControl id="Today.Limits" />
并且一旦调用构造函数就会设置它。
您当然可以在此处创建自己的属性,而不是使用 id,这可能是 fxml 将信息传递到自定义控件实例而不是使用 css id 更合适的方式。
关于java - fxml 中定义的自定义控件 - 如何获取父 ID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23017604/