You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改弹窗所属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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:35:32