如何修改弹窗所属Stage的GUI元素?JavaFX双向通信问题求助
问题描述
我正在实现一个功能:用户点击主界面按钮弹出弹窗,在弹窗输入数据后点击确认,数据要显示在主Stage的标签中。已经实现主Stage向弹窗传数据,但反向传递失败。当前代码运行后,弹窗能关闭,但主Stage的标签内容没变化。
项目代码
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>
问题原因及解决方案
问题根源
SecondaryController中通过FXMLLoader重新加载primary.fxml时,会创建全新的PrimaryController实例和对应的UI组件,这个新实例和主界面正在显示的控制器完全无关,所以调用displayMessage不会对主界面产生任何影响。
修复方案
直接将主界面的PrimaryController引用传递给弹窗控制器,通过该引用操作主界面的UI元素:
修改后的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.setPrimaryController(this); 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.scene.control.TextField; import javafx.stage.Stage; public class SecondaryController { @FXML TextField textField; public Stage stage; // 保存主控制器引用 private PrimaryController primaryController; // 设置主控制器的方法 public void setPrimaryController(PrimaryController primaryController) { this.primaryController = primaryController; } @SuppressWarnings("unused") public void writeToOwner(ActionEvent event) { String message = textField.getText(); // 通过主控制器引用更新主界面 if (primaryController != null) { primaryController.displayMessage(message); } stage.close(); } }
内容的提问来源于stack exchange,提问作者HornedAccomplice
相关产品推荐
相关产品推荐

