JavaFX切换BorderPane的中心:按钮只能工作一次

时间:2017-04-13 18:21:10

标签: java javafx fxml

我在一分钟与JavaFX有点混淆。基本上,当我运行我的代码时,我只能单击应用程序侧栏上的一个按钮,然后它会将中心窗格交换为我想要显示的那个。在那之后,似乎ActionEvent没有触发...我已经尝试在处理后重新连接它们但它不起作用,我不知道什么是错的。

我花了两天的时间试图解决这个问题,我确信这是非常简单的事情。

控制器:

@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中正确注入的,但是一旦中心面板切换,侧面按钮就不再起作用了(虽然我最初可以点击任何一个,但它会加载。

脚注:为了便于阅读,上面的代码略有减少并进行了更改。

2 个答案:

答案 0 :(得分:1)

我从Android的剧本中得到了一个想法。 如果您知道如何访问节点的父节点并且您知道节点的fx:id,则可以使用此方法。

完整代码根据按下哪个按钮将不同的窗格加载到场景的中心。下面的代码是一个示例,显示如何加载一个窗格。如果您知道节点的父节点,节点的fx:id和节点的类型,则可以使用此构思获取任何节点。

  

控制器代码

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中是第二种方法。找到完整代码here。工作但项目不完整。

答案 1 :(得分:0)

此答案与您发布的代码类似。这个答案使用了原始答案中提到的两个相同的想法。

  

主要

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class JavaFXApplication75 extends Application
{

    @Override
    public void start(Stage stage) throws Exception
    {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}
  

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="449.0" prefWidth="564.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication75.FXMLDocumentController">
    <children>
        <Button fx:id="btnMainBar" layoutX="76.0" layoutY="391.0" onAction="#handleButtonAction" text="Load Bar" />
        <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
      <Button fx:id="btnMainFoo" layoutX="419.0" layoutY="391.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Load Foo" />
      <AnchorPane fx:id="apMain" layoutX="161.0" layoutY="88.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="50.0" AnchorPane.topAnchor="25.0" />
    </children>
</AnchorPane>
  

控制器

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;

/**
 *
 * @author blj0011
 */
public class FXMLDocumentController implements Initializable
{    
    @FXML AnchorPane apMain;//This pane will be used to display the other two panes depending on which button is pressed.

    //Foo Pane children nodes
    Button btnFooOne, btnFooTwo;
    TextField tfFooOne, tfFooTwo;
    Label lblFoo;

    //Bar Pane children nodes
    Button btnBar;
    TextField tfBar;
    Label lblBar;

    @FXML
    private void handleButtonAction(ActionEvent event)
    {
        if(((Button)event.getSource()).getId().equals("btnMainBar"))
        {
            loadBarPane();
        }
        else if(((Button)event.getSource()).getId().equals("btnMainFoo"))
        {
            loadFooPane();
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb)
    {
        // TODO
    }   

    //This approach uses the findNodeByID method.
    private void loadFooPane()
    {
        try 
        {
            if(apMain.getChildren().size() > 0)
            {
                apMain.getChildren().remove(0);//if a node is loaded into apMain, remove the node.
            }

            Pane root = FXMLLoader.load(getClass().getResource("Foo.fxml"));
            apMain.getChildren().add(root);//Add Foo Pane to apMain

            //Get Foo Pane's children nodes
            tfFooOne = (TextField)findNodeByID("tfFooOne", root.getChildren());
            tfFooTwo = (TextField)findNodeByID("tfFooTwo", root.getChildren());
            btnFooOne = (Button)findNodeByID("btnFooOne", root.getChildren());
            btnFooTwo = (Button)findNodeByID("btnFooTwo", root.getChildren());
            lblFoo = (Label)findNodeByID("lblFoo", root.getChildren());

            //Set Listeners

            tfFooOne.textProperty().addListener((obserValue, oldValue, newValue) -> {
                lblFoo.setText("new value: " + newValue);
            });

            tfFooTwo.textProperty().addListener((obserValue, oldValue, newValue) -> {
                lblFoo.setText("new value: " + newValue);
            });

            btnFooOne.setOnAction((event) -> {lblFoo.setText("You pressed btnFooOne");});
            btnFooTwo.setOnAction((event) -> {lblFoo.setText("You pressed btnFooTwo");});

        }
        catch (IOException ex) 
        {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void loadBarPane()
    {
        try
        {
            //This way is more complicate if you have more than one of the same type of node
            if(apMain.getChildren().size() > 0)
            {
                apMain.getChildren().remove(0);//if a node is loaded into apMain, remove the node.
            }
            Pane root = FXMLLoader.load(getClass().getResource("Bar.fxml"));
            apMain.getChildren().add(root);//Add Foo Pane to apMain

            //Get Bar Pane's children nodes
            for(Node node : root.getChildren())
            {
                if(node instanceof Button)
                {
                    btnBar = (Button)node;
                }
                else if(node instanceof TextField)
                {
                    tfBar = (TextField)node;
                }
                else if(node instanceof Label)
                {
                    lblBar = (Label)node;
                }
            }

            //Set listeners
            tfBar.textProperty().addListener((obserValue, oldValue, newValue) -> {
                lblBar.setText("new value: " + newValue);
            });

            btnBar.setOnAction((event) -> {lblBar.setText("You pressed btnFooOne");});
        }
        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;
    }


}
  

Foo FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="324.0" prefWidth="464.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Button fx:id="btnFooOne" layoutX="84.0" layoutY="209.0" mnemonicParsing="false" text="Button" />
      <Button fx:id="btnFooTwo" layoutX="329.0" layoutY="209.0" mnemonicParsing="false" text="Button" />
      <TextField fx:id="tfFooOne" layoutX="36.0" layoutY="162.0" />
      <TextField fx:id="tfFooTwo" layoutX="281.0" layoutY="162.0" />
      <Label fx:id="lblFoo" layoutX="165.0" layoutY="39.0" text="You just loaded Foo Pane" />
   </children>
</Pane>
  

Bar FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="324.0" prefWidth="464.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Button fx:id="btnBar" layoutX="206.0" layoutY="186.0" mnemonicParsing="false" text="Button" />
      <TextField fx:id="tfBar" layoutX="158.0" layoutY="130.0" />
      <Label fx:id="lblBar" layoutX="160.0" layoutY="65.0" text="You just loaded Bar Pane" />
   </children>
</Pane>