JavaFX TabPane 选择无法正常工作

JavaFX TabPane selection wont work properly

我有两个带控制器的 *.fxml 表单。第一个是 Window,第二个是 ProductPane。

简化的Window.fxml是:

<BorderPane prefWidth="650.0" prefHeight="450.0" fx:controller="package.WindowController">
    <center>
        <TabPane fx:id="tabsPane">
            <tabs>
                <Tab fx:id="productsTab" text="Products"/>
                <Tab fx:id="warehouseTab" text="Warehouse"/>
                <Tab fx:id="saleTab" text="Sale"/>
            </tabs>
        </TabPane>
    </center>
</BorderPane>

Window.fxml 的控制器:

public class WindowController {
    @FXML
    private TabPane tabsPane;

    @FXML
    private Tab productsTab;

    @FXML
    void initialize() {
        sout("Main Window initialization...");

        tabsPane.getSelectionModel().selectedIndexProperty().addListener((e, o, n) -> {
            sout("Changed to " + n);
        });

        tabsPane.getSelectionModel().selectedItemProperty().addListener((e, o, n) -> {
            sout("New item: " + n);
            // Load ProductPane content:
            if(n == productsTab) {
                try {

                    Parent p = FXMLLoader.load(getClass().getResource("productPane.fxml"));
                    n.setContent(p);

                } catch(IOException ex) {
                    ex.printStackTrace();
                }
            }
        });

        sout("Select first item...");
        tabsPane.getSelectionModel().selectFirst();

        // This methods also don't work
        // tabsPane.getSelectionModel().clearAndSelect();
        // tabsPane.getSelectionModel().select(productTab);
        // tabsPane.getSelectionModel().select(0);
    }
}

问题是:当我在 main() 中加载 Window.fxml 并启动它时,它出现 window,第一个选项卡为空。

调试输出:

Main Window initialization...
Select first item...

但 ProductPane 未加载且侦听器未调用。如果我在 Window 中的选项卡之间切换,则会触发侦听器并正确加载产品选项卡。

有什么问题?

您向选项卡窗格的 selection 模型添加了一个 ChangeListener,当然会在 selection 更改时收到通知。默认情况下,第一个选项卡是 selected,因此在添加更改侦听器时,第一个选项卡已经 selected。这意味着当您调用 selectFirst() 时,selection 不会改变(因为您要求 select 已经 selected 的选项卡),因此听众未收到通知。

解决方案有点难看:如果在添加侦听器时 select 编辑了产品选项卡,则只需直接加载产品选项卡内容即可。我会将该代码分解为一个单独的方法以避免重复太多:

@FXML
void initialize() {
    System.out.println("Main Window initialization...");

    tabsPane.getSelectionModel().selectedIndexProperty().addListener((e, o, n) -> {
        System.out.println("Changed to " + n);
    });

    tabsPane.getSelectionModel().selectedItemProperty().addListener((e, o, n) -> {
        System.out.println("New item: " + n);
        // Load ProductPane content:
        if(n == productsTab) {
            loadProductsTab();
        }
    });

    if (tabPane.getSelectionModel().getSelectedItem() == productsTab) {
        loadProductsTab();
    }
}

private void loadProductsTab() {
    try {

        Parent p = FXMLLoader.load(getClass().getResource("productPane.fxml"));
        productsTab.setContent(p);

    } catch(IOException ex) {
        ex.printStackTrace();
    }
}

如果您发现自己非常需要这种功能,您可能会对 ReactFX 框架感兴趣,它(我认为)具有处理此类情况的内置功能。