我一直在开发一个具有 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
应该接收它自己的事件处理程序方法。即使代码足够相似,您也应该避免检查源与某些节点的引用相等性。相反,您可以将信息存储在 Node
的 userData
或 properties
中。
推荐
使用您的 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/