简体   繁体   中英

How can I alter GUI elements of a stages owner?

I'm currently trying to figure out how to implement a feature in which the user clicks a button and a popup appears, and then the user enters data into that popup, clicks a confirm button, and the data becomes visible in the popups owner. I was able to make data from the owner stage carry over to the popup stage after follow Bro Code's tutorial on making controllers communicate, however getting it to work the other way around is proving troublesome. Below is a project in which I've isolated the issue to try and figure it out.

App.java

package org.example;

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

import java.util.Objects;

public class App extends Application {

    public static Stage stage;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("primary.fxml")));
        Scene scene = new Scene(root);
        stage = new Stage();
        stage.setScene(scene);
        stage.show();
    }

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

PrimaryController.java

package org.example;

import java.io.IOException;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class PrimaryController {

    @FXML
    Label label;

    @SuppressWarnings("unused")
    public void login(ActionEvent event) throws IOException{
        FXMLLoader loader = new FXMLLoader(getClass().getResource("secondary.fxml"));
        Parent root = loader.load();

        SecondaryController secondaryController = loader.getController();
        secondaryController.stage = new Stage();
        secondaryController.stage.initModality(Modality.APPLICATION_MODAL);
        secondaryController.stage.initOwner(App.stage);

        Scene scene = new Scene(root);
        secondaryController.stage.setScene(scene);
        secondaryController.stage.show();
    }

    public void displayMessage(String message){
        label.setText(message);
    }
}

SecondaryController.java

package org.example;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class SecondaryController {

    @FXML
    TextField textField;

    public Stage stage;

    @SuppressWarnings("unused")
    public void writeToOwner(ActionEvent event) throws IOException {
        String message = textField.getText();

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

        PrimaryController primaryController = loader.getController();
        primaryController.displayMessage(message);
        stage.close();
    }
}

primary.fxml

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

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

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.PrimaryController">
   <children>
      <Button layoutX="270.0" layoutY="230.0" mnemonicParsing="false" onAction="#login" text="Login" />
      <Label fx:id="label" layoutX="280.0" layoutY="191.0" />
   </children>
</AnchorPane>

secondary.fxml

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

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

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.SecondaryController">
   <children>
      <TextField fx:id="textField" layoutX="219.0" layoutY="187.0" onAction="#writeToOwner" />
   </children>
</AnchorPane>

The current behavior that I get from this code is almost what I want, except when the user would submit the text, it closes the popup but doesn't change the popups owner.

In your SecondaryController , it looks like you're creating a second instance of PrimaryController , leaving the first unchanged when invoking writeToOwner() .

One approach is to arrange for the controllers to see a common model, much as they share a common stage in your example. The simplest such model is a single ObservableValue , illustrated here . To see the effect,

  • Add a StringProperty named text to your SecondaryController and make it accessible. In writeToOwner() , simply update the text and the bound label will follow.
    public class SecondaryController {
    
        @FXML
        TextField textField;
    
        public Stage stage;
        private final StringProperty text = new SimpleStringProperty();

        public StringProperty textProperty() {
            return text;
        }
    
        @SuppressWarnings("unused")
        public void writeToOwner(ActionEvent event) throws IOException {
            text.set(textField.getText());
            stage.close();
        }
}
  • In your PrimaryController , bind the label's textProperty() to the textProperty() of the SecondaryController .
    public class PrimaryController {
        
        @FXML
        Label label;
        public StringProperty text = new SimpleStringProperty();
        
        @SuppressWarnings("unused")
        public void login(ActionEvent event) throws IOException {
            …
            secondaryController.stage.initOwner(App.stage);
            label.textProperty().bind(secondaryController.textProperty());
            …
        }
    }

In practice, you'll want to avoid public access to class members.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM