java - 从父 Pane 加载现有 FXML

标签 java javafx parent children pane

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

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

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

我的问题如下:如果我可以向父 Pane 添加一个子 Pane ,首先使用mainPane.getChildren().add(root) ,然后我添加了一个简单的 boolean 开关,如果添加了 Pane 并且已经添加了这种类型的 Pane - 尝试让它显示 mainPane.getChildren().get(intArray[0]).toFront(); 。但是,当将此添加到所有其他按钮处理程序时,.toFront()方法似乎按照添加的顺序显示 Pane 。

所以,如果我最初按下按钮 trackerButton , progressButton , communityButton , blockerButton - 然后我按trackerButton Pane 将显示 4 次 -> trackerPane , progressPane , communityPane , blockerPane如果我继续按下它,然后再次循环这些。

是否有一种更清晰的方法可以实现此目的,这样如果我多次按下按钮,它只会加载关联 Pane ,但不会使用 mainPane.getChildren().add(root); 添加它的新实例。 ?

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

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 会导致节点移动到父布局的最后一个索引。这会导致某些指数在某些情况下变得错误。要解决此问题,只需在数据结构中存储节点,而不是索引。

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

@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 应该接收它自己的事件处理程序方法。即使代码足够相似,您也应该避免检查源与某些节点的引用相等性。相反,您可以将信息存储在 NodeuserDataproperties 中。

推荐

使用您的 Controller 实现以下接口(interface):

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();
}

关于java - 从父 Pane 加载现有 FXML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51776539/

相关文章:

具有微秒或纳秒精度的 Java 日期解析

java - 在JNI中直接获取DirectByteBuffer地址的风险

javascript - 获取包含div的ID以传入jeditable jquery

java - 整数对象未在比较器的比较函数中进行比较

java - 卸载/安装 JDK

javafx - 更新JavaFX中的两个文本对象,一个接一个,只看到两个更改的最终结果

没有 GUI 的 JavaFX

java - 生物特征认证java应用程序。如何建立智能手机和应用程序之间的连接

java 。移动与子级具有相同标签名称的 xml

css - 相对于父 div 的固定位置