从父窗格加载现有 FXML
Load existing FXML from parent pane
我一直在开发一个具有 mainPane 窗格的应用程序,该窗格在其中存储多个较小的窗格。
我最初是通过为每个按下的按钮添加一个侦听器开始的,当按下一个特定的按钮时,应该会出现一个相关的窗格。这工作得很好,直到我意识到我在每次按下按钮时添加了一个新的窗格实例,并最终在后台某处丢失了最初选择的窗格的进度。
从那以后,我尝试尝试从主父窗格的 getChildren() 方法加载现有窗格,但是我在这方面没有取得多大成功。我试图在这里到处找到解决方案,但我找不到任何与我的问题相关的东西,或者如果我发现了一些我可能根本不理解的东西。
我的问题如下:如果我可以将子窗格添加到父窗格以开始使用 mainPane.getChildren().add(root)
,然后我添加了一个简单的布尔开关来设置是否添加了窗格,如果这种类型的面板已经被添加 - 尝试让它与 mainPane.getChildren().get(intArray[0]).toFront();
一起显示。但是,将此添加到所有其他按钮处理程序时,.toFront()
方法似乎按添加顺序显示窗格。
因此,如果我最初按下按钮 trackerButton
、progressButton
、communityButton
、blockerButton
- 然后按下 trackerButton
4 次,窗格将显示-> trackerPane
、progressPane
、communityPane
、blockerPane
如果我一直按它,然后再次循环这些。
有没有更简洁的方法来实现这个,这样如果我多次按下一个按钮,它只会加载它的相关窗格,但不会使用 [=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
应该接收它自己的事件处理程序方法。即使代码足够相似,您也应该避免检查源与您的某些节点的引用相等性。相反,您可以将信息存储在 userData
或 Node
的 properties
中。
推荐
使用您的控制器实现以下接口:
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();
}
我一直在开发一个具有 mainPane 窗格的应用程序,该窗格在其中存储多个较小的窗格。
我最初是通过为每个按下的按钮添加一个侦听器开始的,当按下一个特定的按钮时,应该会出现一个相关的窗格。这工作得很好,直到我意识到我在每次按下按钮时添加了一个新的窗格实例,并最终在后台某处丢失了最初选择的窗格的进度。
从那以后,我尝试尝试从主父窗格的 getChildren() 方法加载现有窗格,但是我在这方面没有取得多大成功。我试图在这里到处找到解决方案,但我找不到任何与我的问题相关的东西,或者如果我发现了一些我可能根本不理解的东西。
我的问题如下:如果我可以将子窗格添加到父窗格以开始使用 mainPane.getChildren().add(root)
,然后我添加了一个简单的布尔开关来设置是否添加了窗格,如果这种类型的面板已经被添加 - 尝试让它与 mainPane.getChildren().get(intArray[0]).toFront();
一起显示。但是,将此添加到所有其他按钮处理程序时,.toFront()
方法似乎按添加顺序显示窗格。
因此,如果我最初按下按钮 trackerButton
、progressButton
、communityButton
、blockerButton
- 然后按下 trackerButton
4 次,窗格将显示-> trackerPane
、progressPane
、communityPane
、blockerPane
如果我一直按它,然后再次循环这些。
有没有更简洁的方法来实现这个,这样如果我多次按下一个按钮,它只会加载它的相关窗格,但不会使用 [=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
应该接收它自己的事件处理程序方法。即使代码足够相似,您也应该避免检查源与您的某些节点的引用相等性。相反,您可以将信息存储在 userData
或 Node
的 properties
中。
推荐
使用您的控制器实现以下接口:
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();
}