JavaFX StackPane无法从方法

时间:2018-11-10 01:09:34

标签: java javafx fxml

好的,我用一个更简单的小例子重新编辑了这个问题。

我的问题是,我有一个StackPane,myStackPane,我正在尝试将Label加载到其中。程序首次运行时,StackPane为空。当我单击handleButtonAction按钮时,它将带我进入另一个阶段,因此我可以在标签上输入所需的文本。保存新文本后,它将新设置传递回主控制器并更新标签文本。然后将标签添加到StackPane。

但是...。它不在堆栈窗格中显示新标签。我知道我正在使用该方法,并且可以正确传递变量,因为我可以System.out.println进行所有操作,而且都非常合适。但是为什么不将其添加到StackPane中呢?

谢谢大家!

Problems.java

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

public class Problems 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);
    }

}

FXMLDocumentController

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class FXMLDocumentController implements Initializable {

    @FXML
    private Button button;
    @FXML
    private StackPane myStackPane;

    private Label label = new Label("Text 1");

    @FXML
    private void handleButtonAction(ActionEvent event) {
        FXMLLoader secondLoader = new FXMLLoader();

        secondLoader.setLocation(getClass().getResource("FXMLSecond.fxml"));

        try {
            secondLoader.load();
        } catch (IOException e) {
        }

        FXMLSecondController secondController = secondLoader.getController();

        secondController.setFieldText(label.getText());

        Parent p = secondLoader.getRoot();
        Stage stage = new Stage();
        stage.setScene(new Scene(p));
        stage.showAndWait();
    }

    public void putLabelOnStackPane(String value) {
        label.setText(value);

        myStackPane.getChildren().add(label);
    }

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

}

FXMLSecondController

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

public class FXMLSecondController implements Initializable {

    @FXML
    private Button saveText;
    @FXML
    private TextField textField;

    /**
     * Initializes the controller class.
     */


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

    @FXML
    private void saveTextBtnPressed(ActionEvent event) {
        FXMLLoader firstLoader = new FXMLLoader();

        firstLoader.setLocation(getClass().getResource("FXMLDocument.fxml"));

        try {
            firstLoader.load();
        } catch (IOException e) {
        }

        FXMLDocumentController firstController = firstLoader.getController();

        firstController.putLabelOnStackPane(textField.getText());

        Stage stage = (Stage) saveText.getScene().getWindow();
        stage.close();
    }

    public void setFieldText(String value) {
        textField.setText(value);
    }

}

FXMLDocument

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

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

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="problems.FXMLDocumentController">
    <children>
        <Button fx:id="button" layoutX="128.0" layoutY="14.0" onAction="#handleButtonAction" text="Click Me!" />
      <StackPane fx:id="myStackPane" layoutX="61.0" layoutY="45.0" prefHeight="150.0" prefWidth="200.0" />
    </children>
</AnchorPane>

FXMLSecond

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

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


<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/10.0.1" fx:controller="problems.FXMLSecondController">
   <children>
      <Button fx:id="saveText" layoutX="274.0" layoutY="106.0" mnemonicParsing="false" onAction="#saveTextBtnPressed" text="Button" />
      <TextField fx:id="textField" layoutX="226.0" layoutY="175.0" />
   </children>
</AnchorPane>

1 个答案:

答案 0 :(得分:1)

主要问题是

FXMLLoader firstLoader = new FXMLLoader();
firstLoader.setLocation(getClass().getResource("FXMLDocument.fxml"));

您实际上构造了一个新的FXMLLoader,而不是获得对打开的引用。
例如,可以使用静态成员(请参见here)来获取对打开的FXMLLoader的引用,但最好使用稍微不同的方法:

FXMLDocumentController.java

public class FXMLDocumentController implements Initializable {

    @FXML
    private Button button;
    @FXML
    private StackPane myStackPane;

    private Label label = new Label("Text 1");

    @FXML
    private void handleButtonAction(ActionEvent event) {

        FXMLLoader secondLoader = new FXMLLoader();
        secondLoader.setLocation(getClass().getResource("FXMLSecond.fxml"));

        try {
            secondLoader.load();
        } catch (IOException e) {e.printStackTrace();  }

        FXMLSecondController secondController = secondLoader.getController();
        //secondController.setFieldText(label.getText());
        secondController.setTextProperty(label.textProperty());

        Parent p = secondLoader.getRoot();
        Stage stage = new Stage();
        stage.setScene(new Scene(p));
        stage.showAndWait();
        myStackPane.getChildren().add(label);
    }

    /*
    public void putLabelOnStackPane(String value) {
        label.setText(value);

        myStackPane.getChildren().add(label);
    }*/

    @Override
    public void initialize(URL url, ResourceBundle rb) { //no need to implement Initializable 
                                                         //if initialize not used 
    }    
}

FXMLSecondController.java

public class FXMLSecondController implements Initializable {

    @FXML
    private Button saveText;
    @FXML
    private TextField textField;

    private StringProperty labelStringProperty;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        textField.setEditable(true);
    }    

    @FXML
    private void saveTextBtnPressed(ActionEvent event) {

        /** By doing so you actually construct a new FXMLDocument
        FXMLLoader firstLoader = new FXMLLoader();
        firstLoader.setLocation(getClass().getResource("FXMLDocument.fxml"));

        try {
            firstLoader.load();
        } catch (IOException e) {
        }

        FXMLDocumentController firstController = firstLoader.getController();
        firstController.putLabelOnStackPane(textField.getText());
        */
        labelStringProperty.set(textField.getText());
        Stage stage = (Stage) saveText.getScene().getWindow();
        stage.close();
    }

    /*
    public void setFieldText(String value) {
        textField.setText(value);
    }*/

    public void setTextProperty(StringProperty labelStringProperty) {
        this.labelStringProperty = labelStringProperty;
        textField.setText(labelStringProperty.get());
    }
}

还可以考虑使用Dialog作为输入。

编辑 要让FXMLSecondControllerFXMLDocoment上添加标签,请更改FXMLDocumentController以将所需的引用传递给FXMLSecondController

public class FXMLDocumentController {

    @FXML
    private Button button;
    @FXML
    private StackPane myStackPane;

    private Label label = new Label("Text 1");

    @FXML
    private void handleButtonAction(ActionEvent event) {

        FXMLLoader secondLoader = new FXMLLoader();
        secondLoader.setLocation(getClass().getResource("FXMLSecond.fxml"));

        try {
            secondLoader.load();
        } catch (IOException e) {e.printStackTrace();  }

        FXMLSecondController secondController = secondLoader.getController();
        secondController.setRefrences(myStackPane.getChildren(), label);

        Parent p = secondLoader.getRoot();
        Stage stage = new Stage();
        stage.setScene(new Scene(p));
        stage.showAndWait();
    } 
}

并让FXMLSecondController使用这些引用:

public class FXMLSecondController {

    @FXML
    private Button saveText;
    @FXML
    private TextField textField;

    private ObservableList<Node> children;
    private Label label;

    @FXML
    private void saveTextBtnPressed(ActionEvent event) {

        label.setText(textField.getText());
        children.add(label);
        Stage stage = (Stage) saveText.getScene().getWindow();
        stage.close();
    }

    public void setRefrences(ObservableList<Node> children, Label label) {      
        this.children = children;
        this.label = label;
        textField.setText(label.getText());
    }
}