Java 从控制器访问FXML中的重复控件,而无需为每个控件提供ID

Java 从控制器访问FXML中的重复控件,而无需为每个控件提供ID,java,javafx,javafx-8,javafx-2,Java,Javafx,Javafx 8,Javafx 2,这就是我的FXML层次结构的外观: 锚烷 VBox HBox 组合框:字符串:[频道名称] TextField:[启动前延迟] 按钮:[触发录制开始] HBox 组合框:字符串:[频道名称] TextField:[启动前延迟] 按钮:[触发录制开始] HBox 组合框:字符串:[频道名称] TextField:[启动前延迟] 按钮:[触发录制开始] 我想要一种方法来访问每个hbox——在我的控制器中————内部的控件,而不必给它内部的每个控件一个id 我现在做的是使用每个

这就是我的FXML层次结构的外观:

  • 锚烷
    • VBox
      • HBox
        • 组合框:字符串:[频道名称]
        • TextField:[启动前延迟]
        • 按钮:[触发录制开始]
      • HBox
        • 组合框:字符串:[频道名称]
        • TextField:[启动前延迟]
        • 按钮:[触发录制开始]
      • HBox
        • 组合框:字符串:[频道名称]
        • TextField:[启动前延迟]
        • 按钮:[触发录制开始]
我想要一种方法来访问每个hbox
——在我的控制器中——
——内部的控件,而不必给它内部的每个控件一个id

我现在做的是使用每个元素的索引来获得 像这样抓住它:

@FXML
公共无效开始记录(MouseeEvent事件){
ObservableList curChildNodes=((节点)event.getTarget()).getParent().getChildrenUnmodifiable();
字符串channelName=((组合框)(curChildNodes.get(0)).getSelectionModel().getSelectedItem();
long delay=long.parseLong(((TextField)curChildNodes.get(1)).getText());
流=新流(信道名称、延迟);
记录器=新记录器(流);
recorder.startAfterDelay();
}
如果我在HBox中有更多控件,或者如果我决定更改它们在层次结构中的位置,我使用的方法可能会变得单调乏味


有更好的方法吗?

使用
组合框
文本字段
按钮
创建一个单独的FXML文件(带有自己的控制器类),表示
HBox
。然后使用将其包含在主FXML文件中

如果需要,您可以使用该技术引用为“主”控制器中包含的FXML文件的每个实例创建的控制器实例

因此,您可以创建类似这样的内容(我将其称为
ChannelControls.fxml
):


带控制器

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());
        // ...
    }
}
然后,您可以通过在
fx:id
值中添加
“Controller”
来访问控制器:

public class MainController {

    @FXML
    private ChannelController channel1Controller ;
    @FXML
    private ChannelController channel2Controller ;

    public void initialize() {
        // do anything you need with channel1Controller, etc.
    }
}

在此基础上的一个微小变化是实现
HBox
,并将其作为一个组件。这实际上只是颠倒了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
}
现在您的主fxml文件只需要



您可以将
fx:id
s添加到
元素中,并根据需要将它们直接注入主控制器。这种方法使得在
ChannelControls
类中公开属性和方法,并在主控制器imho中访问它们变得稍微容易一些。

没有一个javafx问题会在只有James\D!我现在就试试,谢谢!非常感谢你,詹姆斯!工作完美无瑕!另外,我很感谢你抽出时间来写这个全面的答案,很少有人这样做。
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
}