这就是我的 FXML 层次结构:
我想要一种方法来获取每个hbox -in my controller-
内部的控件,而不必为其中的每个控件提供id。
我目前正在做的是使用每个元素的索引来获取a 坚持这样:
@FXML
public void startRecording(MouseEvent event) {
ObservableList<Node> curChildNodes = ((Node) event.getTarget()).getParent().getChildrenUnmodifiable();
String channelName = ((ComboBox<String>) (curChildNodes.get(0))).getSelectionModel().getSelectedItem();
long delay = Long.parseLong(((TextField) curChildNodes.get(1)).getText());
Stream stream = new Stream(channelName, delay);
Recorder recorder = new Recorder(stream);
recorder.startAfterDelay();
}
如果我在HBox中有更多控件,或者如果我决定更改他们在层次结构中的位置,我使用的方法可能会乏味。
有更好的方法吗?
答案 0 :(得分:2)
使用HBox
,ComboBox
和TextField
创建一个单独的FXML文件(带有自己的控制器类),代表Button
。然后使用<fx:include>
将其包含在主FXML文件中。
如果需要,您可以使用"Nested Controllers"技术在“主”控制器中引用为所包含的FXML文件的每个实例创建的控制器实例。
所以你可以创建这样的东西(我称之为ChannelControls.fxml
):
<HBox xmlns:fx="..." fx:controller="myapp.ChannelController">
<ComboBox fx:id="channel"/>
<TextField fx:id="delay"/>
<Button text="Start" fx:id="start" onAction="startRecording"/>
</HBox>
带控制器
public class ChannelController {
@FXML
private ComboBox<String> channel ;
@FXML
private TextField delay ;
@FXML
private Button start ;
@FXML
private void startRecording(ActionEvent event) {
String channelName = channel.getValue();
long delayTime = Long.parseLong(delay.getText());
// ...
}
}
然后在你的“主”fxml中,你可以做到
<AnchorPane xmlns:fx="..." fx:controller="myapp.MainController" >
<VBox>
<fx:include src="ChannelControls.fxml"/>
<fx:include src="ChannelControls.fxml"/>
<fx:include src="ChannelControls.fxml"/>
</VBox>
</AnchorPane>
如果您需要访问主控制器中ChannelController
的实例,请将fx:id
添加到<fx:include>
s:
<fx:include src="ChannelControls.fxml" fx:id="channel1" />
<fx:include src="ChannelControls.fxml" fx:id="channel2" />
<!-- etc -->
然后您可以通过将"Controller"
附加到fx:id
值来访问控制器:
public class MainController {
@FXML
private ChannelController channel1Controller ;
@FXML
private ChannelController channel2Controller ;
public void initialize() {
// do anything you need with channel1Controller, etc.
}
}
这方面的一个细微变体是将HBox
及其作品"Custom Component"实施。这实际上只是颠倒了FXML文件和控制器类的创建角色(因此,您不必加载FXML文件,而是自动创建控制器,而是创建控制器,自动加载FXML)。所以你可以创建
public class ChannelControls extends HBox {
@FXML
private ComboBox<String> channel ;
@FXML
private TextField delay ;
@FXML
private Button start ;
public ChannelControls() {
try {
FXMLLoader loader = new FXMLLoader("ChannelControls.fxml");
loader.setRoot(this);
loader.setController(this);
loader.load();
} catch (IOException exc) {
// this is pretty much fatal:
throw new UncheckedIOException(exc);
}
}
@FXML
private void startRecording(ActionEvent event) {
String channelName = channel.getValue();
long delayTime = Long.parseLong(delay.getText());
// ...
}
// other methods as needed
}
对ChannelControls.fxml
的唯一更改是根元素:请注意,您必须删除fx:controller
属性:
<fx:root type="HBox" xmlns:fx="...">
<ComboBox fx:id="channel"/>
<TextField fx:id="delay"/>
<Button text="Start" fx:id="start" onAction="startRecording"/>
</fx:root>
现在您的主要fxml文件只需要
<AnchorPane xmlns:fx="..." fx:controller="myapp.MainController" >
<VBox>
<ChannelControls/>
<ChannelControls/>
<ChannelControls/>
</VBox>
</AnchorPane>
您可以将fx:id
添加到<ChannelControls>
元素,并根据需要将它们直接注入主控制器。这种方法可以更轻松地公开ChannelControls
类中的属性和方法,并在主控制器imho中访问它们。