JavaFX切换BorderPane的中心:按钮只能使用一次 [英] JavaFX Switching BorderPane's Center: Buttons only work once
问题描述
我当时有点与JavaFX混淆.基本上,运行代码时,我只能单击一次应用程序侧栏上的按钮,然后它将中心窗格替换为我要显示的窗格.不过,在那之后,似乎ActionEvent不会触发...我尝试在处理后重新附加它们,但是它不起作用,而且我也不知道怎么了.
I'm a tad confused with JavaFX at the minute. Basically, when I run my code, I can only click on a button on the side bar of the application once, then it will swap the center pane for the one that I want displayed. After that though, it appears that the ActionEvent does not trigger... I've tried reattaching them after handling but it doesn't work, and I have no idea whats wrong.
我花了2天的时间来解决这个问题,我敢肯定这是如此烦人的简单.
I've spent 2 days trying to crack this, and I'm sure it's something so annoyingly simple.
控制器:
@FXML private Button fooButton, barButton;
@FXML private Pane fooPane, barPane;
@FXML private BorderPane mainWindow;
@FXML private TabPane tabPane;
@FXML private VBox buttonBar;
@FXML private AnchorPane centerAP;
private HashMap<Button, Pane> buttonsPaneHMap = new HashMap<>(); //storing the data in a HashMap to create a link between buttons and their panes.
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
putNodesInHashmap();
assertControlsExist();
mainWindow.setCenter(welcomePane);
setOnActions(buttonsPaneHMap);
}
public final void handleButton(ActionEvent event) throws IOException {
Node newCenter = new AnchorPane();
if (event.getSource() == fooButton){
newCenter = FXMLLoader.load(getClass().getResource("/FXML/fooPane.fxml"));
}
if (event.getSource() == barButton){
newCenter = FXMLLoader.load(getClass().getResource("/FXML/barPane.fxml"));
}
try{
this.mainWindow.setCenter(newCenter);
}
catch (NullPointerException e){
e.printStackTrace();
}
}
public final void setOnActions(HashMap<Button, Pane> hMap){
for (Button button : hMap.keySet()){
((ButtonBase) button).setOnAction(arg0 -> {
try {
handleButton(arg0);
}
catch (Exception e) {
e.printStackTrace();
}
});
}
}
public final void putNodesInHashMap(){
buttonsPaneHMap.put(fooButton, fooPane);
buttonsPaneHMap.put(barButton, barPane);
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<BorderPane fx:id="mainWindow" prefHeight="461.0" prefWidth="760.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="guiControllers.MainController">
<top>
<Pane id="body" prefHeight="96.0" prefWidth="658.0" style="-fx-background-color: #243242; -fx-border-color: #0E141B; -fx-border-radius: 3;" stylesheets="@application.css" BorderPane.alignment="CENTER">
<children>
<Label layoutX="103.0" layoutY="25.0" prefHeight="48.0" prefWidth="394.0" text="Title Here" textFill="WHITE">
<font>
<Font name="Calibri Bold" size="41.0" />
</font>
</Label>
<ImageView fitHeight="55.0" fitWidth="61.0" layoutX="25.0" layoutY="20.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../Res/mhlogo.png" />
</image>
</ImageView>
</children>
</Pane>
</top>
<left>
<VBox id="buttonBar" fx:id="buttonBar" alignment="TOP_CENTER" prefHeight="365.0" prefWidth="168.0" style="-fx-background-color: #2E4055; -fx-border-radius: 3; -fx-border-color: #0E141B;" BorderPane.alignment="CENTER">
<children>
<Pane prefHeight="31.0" prefWidth="98.0">
<children>
<Pane layoutX="-1.0" layoutY="-2.0" prefHeight="33.0" prefWidth="169.0" style="-fx-background-color: #565656; -fx-border-color: #000000; -fx-border-radius: 20; -fx-background-radius: 20;">
<children>
<ImageView fitHeight="19.0" fitWidth="18.0" layoutX="7.0" layoutY="7.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../Res/magnifying-glass.png" />
</image>
</ImageView>
<TextField layoutX="29.0" layoutY="2.0" prefHeight="0.0" prefWidth="134.0" style="-fx-border-radius: 1; -fx-border-color: #111111; -fx-border-width: 2; -fx-background-color: #FFFFFF; -fx-background-radius: 20; -fx-border-radius: 20;" styleClass="stop-color-leaking" stylesheets="@../cSS/application.css" />
</children>
</Pane>
</children>
</Pane>
<Button id="fooButton" fx:id="fooButton" mnemonicParsing="false" onAction="#handleButton" prefHeight="31.0" prefWidth="171.0" style="-fx-background-color: #CDCDCD; -fx-border-color: #0E141B; -fx-border-radius: 3;" text="foo" />
<Button id="barButton" fx:id="barButton" mnemonicParsing="false" onAction="#handleButton" prefHeight="31.0" prefWidth="202.0" style="-fx-background-color: #CDCDCD; -fx-border-color: #0E141B; -fx-border-radius: 3;" text="bar" />
<children>
<ImageView id="settingsButton" fitHeight="38.0" fitWidth="48.0" layoutX="64.0" layoutY="130.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../Res/settings.png" />
</image>
</ImageView>
</children>
</AnchorPane>
</children>
</VBox>
</left>
<right>
<TabPane id="tabPane" fx:id="tabPane" focusTraversable="false" prefHeight="365.0" prefWidth="166.0" rotateGraphic="true" style="-fx-background-color: # #414760;" styleClass="tab-header-background" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
<tabs>
<Tab fx:id="notesTab" text="Notes">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="336.0" prefWidth="216.0" style="-fx-border-color: #414760; -fx-background-radius: 3;" styleClass="tab-header-background" stylesheets="@../application/CSS/application.css" />
</content>
</Tab>
<Tab fx:id="diagramTab" closable="false" text="Diagram" />
</tabs>
<cursor>
<Cursor fx:constant="DEFAULT" />
</cursor>
<stylesheets>
<URL value="@application.css" />
<URL value="@../application/CSS/application.css" />
</stylesheets>
</TabPane>
</right>
<center>
<AnchorPane fx:id="centerAP" style="-fx-background-color: #414760;" BorderPane.alignment="CENTER">
<children>
<VBox fx:id="welcomePane" prefHeight="304.0" prefWidth="391.0" style="-fx-background-color: #414760;">
<children>
<Pane fx:id="welcomePane" prefHeight="313.0" prefWidth="428.0" style="-fx-background-color: #414760;">
<children>
<ImageView fitHeight="183.0" fitWidth="296.0" layoutX="14.0" layoutY="65.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../Res/welcomepane.png" />
</image>
</ImageView>
<Label layoutX="141.0" layoutY="14.0" text="Welcome" textFill="WHITE">
<font>
<Font name="Calibri Bold" size="33.0" />
</font>
</Label>
<Label layoutX="82.0" layoutY="53.0" prefHeight="68.0" prefWidth="346.0" text="To start, please select an" textFill="WHITE" textOverrun="CLIP">
<font>
<Font name="Calibri" size="24.0" />
</font>
</Label>
<Label layoutX="82.0" layoutY="80.0" prefHeight="68.0" prefWidth="346.0" text="option from the left." textFill="WHITE" textOverrun="CLIP">
<font>
<Font name="Calibri" size="24.0" />
</font>
</Label>
</children>
</Pane>
</children>
</VBox>
</children>
</AnchorPane>
</center>
</BorderPane>
据我所知,所有对象都是从FXML正确注入的,但是一旦中心面板切换,侧面按钮将不再起作用(尽管我可以单击任何初始按钮,它将加载.
As far as I can tell all objects are injected correctly from the FXML, but once the center panel has switched, the side buttons no longer function (Though I can click any initially and it will load.
脚注:上面的代码已被稍微缩减并进行了更改以提高可读性.
Footnote: The code above is slightly cut down and changed for readability.
推荐答案
我从Android的剧本中得到了一个想法. 如果您知道如何到达节点的父节点,并且知道节点的fx:id,则可以使用这种方法.
I took an idea from Android's playbook. If you know how to get to the node's parent and you know the node's fx:id, you can use this approach.
完整代码根据按下哪个按钮将不同的窗格加载到场景的中心.下面的代码是一个示例,显示了如何加载一个窗格.如果知道节点的父节点,节点的fx:id和节点的类型,则可以使用此想法获得任何节点.
The full code loads different panes into the center of a Scene depending on which button is press. The code below is a sample that show how one pane is loaded. You can get any node using this idea if you know the node's parent, the node's fx:id and the node's type for casting.
控制器代码
Controller code
private void showSetupAccountScreen()
{
try
{
spCenterDisplay.getChildren().remove(0);//remove old display
BorderPane root = FXMLLoader.load(getClass().getResource("SubSetupAccount.fxml"));
spCenterDisplay.getChildren().add(root);//add new display
GridPane tempDisplay = (GridPane)root.getChildren().get(1);//get Parent of the nodes I will be using in this controller
loadQWERTYKeyboard();
TextField tfFirstName = (TextField)findNodeByID("tfFirstName", tempDisplay.getChildren());
TextField tfLastName = (TextField)findNodeByID("tfLastName", tempDisplay.getChildren());
TextField tfStreetAddress = (TextField)findNodeByID("tfStreetAddress", tempDisplay.getChildren());
TextField tfCity = (TextField)findNodeByID("tfCity", tempDisplay.getChildren());
TextField tfState = (TextField)findNodeByID("tfState", tempDisplay.getChildren());
TextField tfZip = (TextField)findNodeByID("tfZip", tempDisplay.getChildren());
TextField tfInitialDepositChecking = (TextField)findNodeByID("tfInitialDepositChecking", tempDisplay.getChildren());
TextField tfInitialDepositSavings = (TextField)findNodeByID("tfInitialDepositSavings", tempDisplay.getChildren());
ChoiceBox cbChecking = (ChoiceBox)findNodeByID("cbChecking", tempDisplay.getChildren());
cbChecking.getItems().addAll("No", "Yes");
cbChecking.setValue("No");
ChoiceBox cbSavings = (ChoiceBox)findNodeByID("cbSavings", tempDisplay.getChildren());
cbSavings.getItems().addAll("No", "Yes");
cbSavings.setValue("No");
if(true)//come back and check to make sure all info is in textfields
{
btnLeftOne.setOnAction((event) -> {
boolean createChecking = cbChecking.getValue().equals("Yes");
boolean createSavings = cbSavings.getValue().equals("Yes");
dbh.createNewAccount(tfFirstName.getText(), tfLastName.getText(), tfStreetAddress.getText(), tfCity.getText(),
tfState.getText(), tfZip.getText(), createChecking, Double.parseDouble(tfInitialDepositChecking.getText()),
createSavings, Double.parseDouble(tfInitialDepositSavings.getText()));
});
}
else
{
//create Alert
}
btnRightOne.setOnAction((event) -> {
cancelAccountCreation();
});
btnLeftTwo.setOnAction(null);
btnLeftThree.setOnAction(null);
btnLeftFour.setOnAction(null);
btnRightTwo.setOnAction(null);
btnRightThree.setOnAction(null);
btnRightFour.setOnAction(null);
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void loadQWERTYKeyboard()
{
try
{
AnchorPane keyboardRoot = FXMLLoader.load(getClass().getResource("KeyboardQWERTY.fxml"));
System.out.println(keyboardRoot.getId());
spBottomDisplay.getChildren().add(keyboardRoot);
GridPane tempKeyboard = (GridPane)keyboardRoot.getChildren().get(0);
tempKeyboard.getChildren().stream().filter((tempNode)
-> (tempNode instanceof Button)).map((
tempNode) -> (Button) tempNode).forEachOrdered((tempButton) -> {
buttons.put(tempButton.getText().toLowerCase(), tempButton);
});
apMain.setOnKeyPressed((event) -> {
Button tempButton = buttons.get(event.getText());
if (tempButton != null) {
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
else if (event.getCode().equals(KeyCode.ENTER)) {
tempButton = buttons.get("enter");
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
else if (event.getCode().equals(KeyCode.BACK_SPACE)) {
tempButton = buttons.get("backspace");
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
else if (event.getCode().equals(KeyCode.SPACE)) {
tempButton = buttons.get("space");
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
});
apMain.setOnKeyReleased((event) -> {
System.out.println();
Button tempButton = buttons.get(event.getText());
System.out.println("Released key text: " + event.getText());
System.out.println("Released key code: " + event.getCode());
if (tempButton != null) {
tempButton.disarm();
tempButton.setStyle("");
}
else if (event.getCode().equals(KeyCode.ENTER)) {
tempButton = buttons.get("enter");
tempButton.disarm();
tempButton.setStyle("");
}
else if (event.getCode().equals(KeyCode.BACK_SPACE)) {
tempButton = buttons.get("backspace");
tempButton.disarm();
tempButton.setStyle("");
}
else if (event.getCode().equals(KeyCode.SPACE)) {
tempButton = buttons.get("space");
tempButton.disarm();
tempButton.setStyle("");
}
});
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private Node findNodeByID(String id, ObservableList<Node> observableList)
{
for(Node node : observableList)
{
if(node.getId().equals(id))
{
System.out.println("node found!");
return node;
}
else
{
System.out.println("node not found yet!");
}
}
return null;
}
在这段代码中,我使用两种不同的方法.在loadQWERTYKeyboard方法中是一种方法.在findNodeByID中是第二种方法.完整代码可在此处找到.工作正常,但项目尚未完成.
In this snippet of code I use two different approaches. In the loadQWERTYKeyboard methods is one approach. In the findNodeByID is the second approach. The full code is found here. Working but project not complete.
这篇关于JavaFX切换BorderPane的中心:按钮只能使用一次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!