从父窗格加载现有 FXML

Load existing FXML from parent pane

我一直在开发一个具有 mainPane 窗格的应用程序,该窗格在其中存储多个较小的窗格。

我最初是通过为每个按下的按钮添加一个侦听器开始的,当按下一个特定的按钮时,应该会出现一个相关的窗格。这工作得很好,直到我意识到我在每次按下按钮时添加了一个新的窗格实例,并最终在后台某处丢失了最初选择的窗格的进度。

从那以后,我尝试尝试从主父窗格的 getChildren() 方法加载现有窗格,但是我在这方面没有取得多大成功。我试图在这里到处找到解决方案,但我找不到任何与我的问题相关的东西,或者如果我发现了一些我可能根本不理解的东西。

我的问题如下:如果我可以将子窗格添加到父窗格以开始使用 mainPane.getChildren().add(root),然后我添加了一个简单的布尔开关来设置是否添加了窗格,如果这种类型的面板已经被添加 - 尝试让它与 mainPane.getChildren().get(intArray[0]).toFront(); 一起显示。但是,将此添加到所有其他按钮处理程序时,.toFront() 方法似乎按添加顺序显示窗格。

因此,如果我最初按下按钮 trackerButtonprogressButtoncommunityButtonblockerButton - 然后按下 trackerButton 4 次,窗格将显示-> trackerPaneprogressPanecommunityPaneblockerPane 如果我一直按它,然后再次循环这些。

有没有更简洁的方法来实现这个,这样如果我多次按下一个按钮,它只会加载它的相关窗格,但不会使用 [=23= 添加它的新实例] ?

任何帮助将不胜感激,我已将我的代码粘贴在下面:

public class MainController {

private Client client;

@FXML
TrackerPaneController trackerPaneController;

@FXML
ProgressController progressController;

@FXML
CommunityController communityController;

@FXML
BlockerController blockerController;

@FXML
SettingsController settingsController;

@FXML
Label userLabel;

@FXML
Button logoutButton;

@FXML
Button trackerButton;

@FXML
Button progressButton;

@FXML 
Button communityButton;

@FXML
Button blockerButton;

@FXML
Button settingsButton;

@FXML
Pane mainPane;

Integer[] intArray = new Integer[4];
final Boolean[] booleanArray = {true,true,true,true,true};


@FXML
private void handlePanelButtonAction(ActionEvent event) throws IOException {


    if(event.getSource() == trackerButton) {

        if(booleanArray[0]) {


        FXMLLoader trackerLoader = new FXMLLoader(getClass().getResource("/view/TrackerPane.fxml"));
        Parent root = (Parent) trackerLoader.load();

        trackerPaneController = trackerLoader.getController();
        trackerPaneController.setClient(client);
        mainPane.getChildren().add(root);

        intArray[0] = mainPane.getChildren().indexOf(root);

        }

        mainPane.getChildren().get(intArray[0]).toFront();
        booleanArray[0]=false;

    } else if(event.getSource() == progressButton) {

        if(booleanArray[1]) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/ProgressPane.fxml"));
        Parent root = (Parent) loader.load();
        progressController = loader.getController();
        progressController.setClient(client);
        mainPane.getChildren().add(root);
        intArray[1] = mainPane.getChildren().indexOf(root);

        }

        mainPane.getChildren().get(intArray[1]).toFront();
        booleanArray[1]=false;

    } else if(event.getSource() == communityButton) {

        if(booleanArray[2]) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/CommunityPane.fxml"));
        Parent root = (Parent) loader.load();
        communityController = loader.getController();
        communityController.setClient(client);
        mainPane.getChildren().add(root);
        intArray[2] = mainPane.getChildren().indexOf(root);

        }

        mainPane.getChildren().get(intArray[2]).toFront();
        booleanArray[2]=false;

    } else if(event.getSource() == blockerButton) {

        if(booleanArray[3]) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/BlockerPane.fxml"));
        Parent root = (Parent) loader.load();
        blockerController = loader.getController();
        blockerController.setClient(client);
        mainPane.getChildren().add(root);
        intArray[3] = mainPane.getChildren().indexOf(root);

        }

        mainPane.getChildren().get(intArray[3]).toFront();
        booleanArray[3]=false;

    } else if(event.getSource() == settingsButton) {

        if(booleanArray[4]) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/SettingsPane.fxml"));
        Parent root = (Parent) loader.load();
        settingsController = loader.getController();
        settingsController.setClient(client);
        mainPane.getChildren().add(root);
        intArray[4] = mainPane.getChildren().indexOf(root);

        }

        mainPane.getChildren().get(intArray[4]).toFront();
        booleanArray[4]=false;

    } else if(event.getSource() == logoutButton) {

        client.logout();
        Platform.exit();
    }
}

}

我觉得这个解决方案对于具备合适技能的人来说非常简单,但是我对 JavaFX 还是很陌生,我们将不胜感激任何帮助。

亲切的问候

问题是在 Node 上调用 toFront 会导致节点移动到父布局的最后一个索引。这导致某些索引在某些情况下变得错误。要解决此问题,只需存储 Node,而不是数据结构中的索引。

另请注意,除了一些细微差别外,基本上所有加载代码看起来都一样。您应该避免重复代码,因为它会使您的代码更难维护。通过向您的控制器添加一个接口,可以轻松删除重复的代码。

@FXML
private void handlePanelButtonAction(ActionEvent event) throws IOException {
    if(event.getSource() == trackerButton) {
        ...
    } else if(event.getSource() == progressButton) {
        ...
    } else if(event.getSource() == communityButton) {
        ...
    } else if(event.getSource() == blockerButton) {
        ...
    } else if(event.getSource() == settingsButton) {
        ...
    } else if(event.getSource() == logoutButton) {
        ...
    }
}

不要做这样的事情。如果逻辑完全不同,Button 应该接收它自己的事件处理程序方法。即使代码足够相似,您也应该避免检查源与您的某些节点的引用相等性。相反,您可以将信息存储在 userDataNodeproperties 中。

推荐

使用您的控制器实现以下接口:

public interface ClientContainer {
    void setClient(Client client);
}

使用 URL 初始化按钮的 userData

public class MainController {

    ...

    private void setResource(Node node, String resource) {
        URL url = getClass().getResource(resource);
        if (url == null) {
            throw new IllegalArgumentException("Resource not available: " + resource);
        }
        node.setUserData(url);
    }

    private static URL getResource(Object source) {
        return (URL) ((Node) source).getUserData();
    }

    @FXML
    private void initialize() {
        setResource(trackerButton, "/view/TrackerPane.fxml");
        setResource(progressButton, "/view/ProgressPane.fxml");
        setResource(communityButton, "/view/CommunityPane.fxml");
        setResource(blockerButton, "/view/BlockerPane.fxml");
        setResource(settingsButton, "/view/SettingsPane.fxml");
    }
}

使用此数据和 Map 以避免重新加载场景。 (您还需要将处理 logoutButton 点击的代码移动到不同的方法。)

private final Map<URL, Node> loadedContent = new HashMap<>();

@FXML
private void handlePanelButtonAction(ActionEvent event) {
    loadedContent.computeIfAbsent(getResource(event.getSource()), url -> {
        try {
            FXMLLoader loader = new FXMLLoader(url);
            Node result = loader.load();
            ClientContainer controller = loader.getController();
            controller.setClient(client);
            mainPane.getChildren().add(result);
            return result;
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }).toFront();
}