Использование JavaFX для передачи данных в уже открытое окно - PullRequest
1 голос
/ 29 января 2020

Я новичок в JavaFX. Это было легко сделать без F XML, но контроллеры F XML ставят меня в тупик.

Что я пытаюсь сделать: настроить главное окно с кнопкой. При нажатии кнопка запускает второе всплывающее окно, в которое пользователь отправляет значение. После закрытия второго окна (в настоящее время это делается нажатием кнопки во всплывающем окне), я бы хотел, чтобы ввод пользователя был возвращен на главный контроллер - главное окно, которое уже открыто.

Пока у меня есть 2 .f xml файла (один для главного окна, другой для всплывающего окна) и соответствующие контроллеры: MainWindowController:

public class MainController implements Initializable {

@FXML
public Label label;
@FXML
private Button button;


@FXML
private void popBtnClick(ActionEvent event) throws IOException {
    //creates new pop-up window
    Stage popupSave = new Stage();
    popupSave.initModality(Modality.APPLICATION_MODAL);
    popupSave.initOwner(ComWins.stage);

    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("PopUp.fxml"));
    Parent root = loader.load();

    PopUpController controller = loader.getController();

    //calls a method in the PopUpController, and uses it to pass data to 
    //the Popup window.
    controller.dataToPopUp(7);

    Scene scene = new Scene(root);
    popupSave.setScene(scene);
    popupSave.showAndWait();
}

I also tried calling this method from the popup window with no success in 
changing Main's label.
public void dataPass(String name){
    label.setText(name);
}


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

}

И PopUpController:

public class PopUpController implements Initializable {

@FXML
private Button ok_btn; 
@FXML
public TextField input_tf;
@FXML
private String input;




@FXML
private void okBtnClick() throws IOException {
    input = input_tf.getText();

    /*my attempt to pass the variable-- using a loader to get the 
     controller and then referencing the public label. */ 
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("Main.fxml"));
    Parent root = loader.load();


    FXMLDocumentController controller = loader.getController();

    //this line works, and retrieves the label's text.
    String temp = controller.label.getText();

    //but this line does not work. Why? 
    controller.label.setText(input);


    //closes this pop-up
    Stage stage = (Stage)input_tf.getScene().getWindow();
    stage.close();


}

//this method is called in the maincontroller and used to pass data to 
//the popup's textfield.
public void dataToPopUp(int x){
    input_tf.setText(Integer.toString(x));
}


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

}

Используя вышеизложенное, Main передает ('7') в текстовое поле PopUp. Но если пользователь вводит что-то еще в текстовое поле, я не могу вернуть эти данные в Main. Это похоже на всплывающее окно «Настройки», а затем передача выбора пользователя из всплывающего окна «Настройки» обратно в главное окно. Я просто не могу понять, как передать вещи обратно в главное окно.

Я не использую SpringBoot, но спасибо за предложение.

Заранее спасибо!

Ответы [ 3 ]

1 голос
/ 29 января 2020

Если вы используете Spring Boot, у MPV Java на YouTube есть отличные примеры соединения ваших контроллеров, что позволяет вам легко и просто передавать информацию между ними. В моем приложении я смог реализовать эти примеры. Каждый контроллер регистрируется как компонент, используя @Component, что означает, что вы можете @Autowire контроллер подключить к другому контроллеру. В вашем главном контроллере я бы порекомендовал настроить некоторые базовые c геттеры / сеттеры, чтобы разрешить внешнее взаимодействие с вашими полями, чтобы другие контроллеры могли «общаться» с главным контроллером. Действительно базовый c пример был бы:

@Component
public class MyMainController {
    @FXML private TextField exampleTextField;
    ...
    ...
    /* Get the text of a field from this controller: can be accessed from another controller */
    public String getExampleTextField() {
        exampleTextField.getText();
    }
    /* Set the text of a field on this controller: can be accessed from another controller */
    public void setExampleTextField(String text) {
        exampleTextField.setText(text);
    }
}
@Component
public class AnotherController {
    @Autowired private MyMainController myMainController;
    ...
    ...
    public void someMethod(String newText) {
        // Do some work here and set some text back to the main controller
        myMainController.setExampleTextField(newText);
    }
}

MPV Java намного лучше объясняет эту концепцию. https://www.youtube.com/watch?v=hjeSOxi3uPg

0 голосов
/ 04 февраля 2020

Я рассмотрел предложения и не смог заставить что-либо работать на меня - многие концепции были у меня над головой, так как я новичок в Java. После нескольких попыток мне удалось получить довольно простое решение проблемы. Вероятно, это далеко от лучших практик, но это работает:

В контроллере основного окна используйте контроллер всплывающего окна для вызова строковой переменной всплывающего окна и установите его в качестве текста метки (label.setText (controller.test). )). Строковая переменная должна быть publi c и устанавливается после закрытия всплывающего окна нажатием кнопки. См. Код ниже:

Main.f xml:

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="switchingpass.MainController">
    <children>
        <Button fx:id="button" layoutX="126" layoutY="90" onAction="#popBtnClick" text="Click Me!" />
        <Label fx:id="label2" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
      <Label fx:id="label" layoutX="143.0" layoutY="38.0" text="Label" />
    </children>
</AnchorPane>

MainController:

public class MainController implements Initializable {

@FXML
public Label label;
@FXML
private Button button;

@FXML
private void popBtnClick(ActionEvent event) throws IOException {
    //creates new pop-up window
    Stage popupSave = new Stage();
    popupSave.initModality(Modality.APPLICATION_MODAL);
    popupSave.initOwner(SwitchingPass.stage);

    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("PopUp.fxml"));
    Parent root = loader.load();

    PopUpController controller = loader.getController();

    Scene scene = new Scene(root);
    popupSave.setScene(scene);
    popupSave.showAndWait();

    //after the popup closes, this will run, setting the label's text to the popup's test variable, which is public.
    label.setText(controller.test);
}

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

}

PopUp.f xml:

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="switchingpass.PopUpController">
   <children>
      <TextField fx:id="input_tf" layoutX="207.0" layoutY="65.0" />
      <Button fx:id="close_btn" layoutX="268.0" layoutY="185.0" mnemonicParsing="false" onAction="#closeBtnClick" text="Close" />
   </children>
</AnchorPane>

PopUpController:

public class PopUpController implements Initializable {

@FXML
public Button close_btn; 
@FXML
public TextField input_tf;
@FXML
public String test;


@FXML
private void closeBtnClick() throws IOException {

    //stores textfield input as a string    
    test = input_tf.getText();

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

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

}

Обратите внимание, что основной класс кода, расширяющий Application, должен объявить переменную stage как переменную c stati c:

public class SwitchingPass extends Application {

    //this is necessary to initialize the owner of the popup
    public static Stage stage;

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

        Scene scene = new Scene(root);

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

    public static void main(String[] args) {
        launch(args);
    }

}

Опять же, возможно, не лучший способ выполнить это sh, но это работает, и, возможно, это полезно для кого-то еще.

0 голосов
/ 29 января 2020

Я так и сделал. Сначала создайте интерфейс

public interface DataSender {
 void send(String data);
}

, а затем внедрите этот интерфейс в контроллер главного окна

public class FXMLDocumentController implements Initializable,DataSender {

@FXML
private Label label;

@FXML
private void handleButtonAction(ActionEvent event) {

    try {
        Stage popupSave = new Stage();
        popupSave.initModality(Modality.NONE);
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("PopUp.fxml"));
        Parent root = loader.load();

        PopUpController controller = loader.getController();
        controller.setX(7);
        //this is the line use to get data from popup
        controller.setSendDataSender(this);

        Scene scene = new Scene(root);
        popupSave.setScene(scene);
        popupSave.show();
    } catch (IOException ex) {
        Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
    }
}


//this method can call from popus controller
@Override
public void send(String data) {
    label.setText(data);
}

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

, а затем переопределите реализованный метод интерфейса, и в методе вы можете изменить данные интерфейса главного окна I изменил текст метки.

, а затем создайте переменную в контроллер pupup с типом DataSender (созданный интерфейс перед) и создайте метод для установки этого интерфейса

public class PopUpController implements Initializable {

private int x;

//this is the variable
private DataSender dataSender;


@FXML
private Button btnOk;
@FXML
private TextField txtText;

@Override
public void initialize(URL url, ResourceBundle rb) {
    btnOk.setOnAction(e->{
        //When Click this button will call Main Window send method
        dataSender.send(txtText.getText());
    });
}

public void setX(int x){
    this.x=x;
}

//this is the method to set variable value from Main Window
public void setSendDataSender(DataSender ds){
    this.dataSender=ds;
}

}

, а затем при нажатии кнопки всплывающего окна вызовите отправить метод с данными, а затем изменит текст метки главного окна. Это решение работает для меня. Надеюсь, это полезно и для вас.

...