首页 > 解决方案 > 无法通过另一个控制器控制另一个 fxml 文件的元素

问题描述

我正在处理一个处理多个 fxml 和相应的控制器文件的项目。我需要以某种方式从 B.fxml 的控制器访问 A.fxml 中定义的 fxml 元素使用

我不允许显示实际代码。但是,为此,我构建了一个简单的应用程序,其中包含两个 FXML 及其相应的控制器。

此应用程序具有带有 ButtonController.java 的 Button.fxml 和带有 ProgressIndicatorController.java 的 ProgressIndicator.fxml

单击按钮后,进度指示器将生效。

下面是代码:

按钮.fxml

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

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

<AnchorPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ButtonController">
   <children>
      <Pane prefHeight="206.0" prefWidth="281.0">
         <children>
            <Button fx:id="button1" layoutX="59.0" layoutY="63.0" mnemonicParsing="false" prefHeight="63.0" prefWidth="164.0" text="Button" onAction="#onButton1Clicked" />
         </children>
      </Pane>
   </children>
</AnchorPane>

按钮控制器.java

package application;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

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.ProgressIndicator;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ButtonController implements Initializable{

    @FXML
    private Button button1;

    private ProgressIndicator progressIndicator;

    private ProgressIndicatorController progressIndicatorController;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        try {
            Object loader = FXMLLoader.load(getClass().getResource("ProgressIndicator.fxml"));
            Scene sceneProgressIndicator = new Scene((Parent) loader, 1400, 800);
            sceneProgressIndicator.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            sceneProgressIndicator.setFill(Color.TRANSPARENT);
            Stage primaryStageProgressIndicator = new Stage();
            primaryStageProgressIndicator.setScene(sceneProgressIndicator);
            primaryStageProgressIndicator.setResizable(false);
            primaryStageProgressIndicator.setHeight(311);
            primaryStageProgressIndicator.setWidth(523);
            primaryStageProgressIndicator.show();
        } catch (IOException e) {

            e.printStackTrace();
        }




        // TODO Auto-generated method stub



    }

    public void onButton1Clicked() {

        FXMLLoader fxmlLoaderProgressIndicator = new FXMLLoader();
        fxmlLoaderProgressIndicator.setLocation(getClass().getResource("ProgressIndicator.fxml"));
        try {
            Parent root = fxmlLoaderProgressIndicator.load();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        progressIndicatorController = (ProgressIndicatorController) fxmlLoaderProgressIndicator.getController();



        for(double  i = 0.0; i <= 1.0 ; i+=0.2) {
            progressIndicator = progressIndicatorController.getProgressIndicator1();
            progressIndicator.setProgress(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }


}

进度指示器.fxml

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

<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>


<AnchorPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ProgressIndicatorController">
   <children>
      <Pane prefHeight="200.0" prefWidth="200.0">
         <children>
            <ProgressIndicator fx:id="progressIndicator1" layoutX="47.0" layoutY="31.0" prefHeight="103.0" prefWidth="106.0" progress="0.0" />
         </children>
      </Pane>
   </children>
</AnchorPane>

ProgressindicatorController.java

package application;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ProgressIndicatorController implements Initializable {


    @FXML
    private ProgressIndicator progressIndicator1;

    @Override
    public void initialize(URL location, ResourceBundle resources) {




        // TODO Auto-generated method stub

    }

    public ProgressIndicator getProgressIndicator1() {

        System.out.println("getteeerrrrrrrr");
        return progressIndicator1;
    }

    public void setProgressIndicator1(ProgressIndicator progressIndicator1) {
        this.progressIndicator1 = progressIndicator1;
    }

}

getter 方法调用成功。但是,当我单击按钮时,进度指示器不会更新。

我也没有收到任何类型的错误消息。

我遇到了这个链接Javafx - how to accesses FXML "objects" 这确实在很大程度上帮助了我,但我也无法完成这项工作。我只是尝试修改按钮单击方法如下:

onButton1Cliked()

public void onButton1Clicked() {

        progressIndicator = (ProgressIndicator) sceneProgressIndicator.lookup("#progressIndicator1");

        for(double  i = 0.0; i <= 1.0 ; i+=0.2) {
            try {
                System.out.println("Progressingggg   " + i);
                progressIndicator.setProgress(i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

单击按钮确实会打印出报表。但是进度指示器不会随着每个 for 循环迭代而更新。只有最后进度指示器才会更新并显示完成。

知道为什么会这样吗?

除了使用查找方法之外,还有其他方法可以访问 fxml 元素。可以使我以前的方法(尝试通过控制器获取 fxml 元素)以某种方式工作。

欢迎任何意见或建议。一直在这几个小时。Stackoverflow 似乎是最后的手段。

编辑 1:开始

事实证明,由于 Zephyr 第一条评论中解释的原因,进度指示器没有更新。所以我为我的应用程序创建了一个单独的线程,随着进度指示器按预期更新,这似乎工作正常。

成功更新进度指示器的 onButton1Clicked() 方法的工作版本:

public void onButton1Clicked() {

        progressIndicator = (ProgressIndicator) sceneProgressIndicator.lookup("#progressIndicator1");

        Runnable runnable = new Runnable() {

            @Override
            public void run() {

                for(double  i = 0.0; i <= 1.0 ; i+=0.2) {               
                    try {
                        System.out.println("Progressingggg   " + i);
                        progressIndicator.setProgress(i);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
        }   

            }
        };

        Thread thread = new Thread(runnable);
        thread.start();

    }

解决了这个线程问题后,我再次尝试采用我的 OP 中提到的原始方式(即获取 ProgressIndicatorController 实例并访问其进度指示器,然后尝试更新它)。但是,这对我不起作用。我尝试调试,发现我正在取回 ProgressIndicatorController 和 ProgressIndicator 实例。

为什么如果我的代码对进度指示器实例有保留,则它无法更新进度指示器。println 方法执行成功。它只是进度指示器根本没有更新。它一直处于“0”。

不更新 progressIndicator 的 onButton1Clicked() 方法版本:

public void onButton1Clicked() {        

        FXMLLoader fxmlLoaderProgressIndicator = new FXMLLoader();
        fxmlLoaderProgressIndicator.setLocation(getClass().getResource("ProgressIndicator.fxml"));
        try {
            Parent root = fxmlLoaderProgressIndicator.load();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        progressIndicatorController = (ProgressIndicatorController) fxmlLoaderProgressIndicator.getController();



        progressIndicator = progressIndicatorController.getProgressIndicator1();

        Runnable runnable = new Runnable() {

            @Override
            public void run() {

                for(double  i = 0.0; i <= 1.0 ; i+=0.2) {               
                    try {
                        System.out.println("Progressingggg   " + i);
                        progressIndicator.setProgress(i);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
        }   

            }
        };

        Thread thread = new Thread(runnable);
        thread.start();

    }

编辑 1:结束

编辑 2:开始

添加运行此示例应用程序所需的其他文件

主.java

package application;

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


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Object root =FXMLLoader.load(getClass().getResource("Button.fxml"));
            Scene scene = new Scene((Parent) root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }


    }

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

我的application.css文件中没有任何内容。它是空的。

我在Java 8上使用JavaFX8。IDE 是Eclipse Photon

我使用e(fx)clipse插件创建了我的项目,并从创建新项目窗口中选择了JavaFX 项目。

编辑 2:结束

编辑 3:开始

EDIT 1部分下,尝试测试成功更新进度指示器的onButton1Clicked()版本时,请不要忘记将其包含为ButtonController.javaprivate Scene sceneProgressIndicator类的成员变量。

编辑 3:结束

标签: javafxjavafx-8

解决方案


我假设你想要这样的东西(注意评论):

import java.io.IOException;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ButtonController {

    @FXML
    private Button button1;
    private ProgressIndicator progressIndicator;
    private Scene sceneProgressIndicator;

    @FXML
    public void initialize() {

        try {

            FXMLLoader loader = new FXMLLoader(getClass().getResource("ProgressIndicator.fxml"));
            Pane progressIndicatorPane = loader.load();
            ProgressIndicatorController progressIndicatorController  = loader.getController(); //get a reference to the progress indicator controller
            progressIndicator = progressIndicatorController.getProgressIndicator1(); //get the progress indicator 

            sceneProgressIndicator = new Scene(progressIndicatorPane, 1400, 800);
            sceneProgressIndicator.setFill(Color.TRANSPARENT);
            Stage primaryStageProgressIndicator = new Stage();
            primaryStageProgressIndicator.setScene(sceneProgressIndicator);
            primaryStageProgressIndicator.setResizable(false);
            primaryStageProgressIndicator.setHeight(311);
            primaryStageProgressIndicator.setWidth(523);
            primaryStageProgressIndicator.show();
        } catch (IOException e) {

            e.printStackTrace();
        }
    }

    public void onButton1Clicked() {

        Runnable runnable = () -> {

            for(double  i = 0.0; i <= 1.0 ; i+=0.2) {

                final double fD = i;
                Platform.runLater(() -> progressIndicator.setProgress(fD));//update done on javafx thread 

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();
    }
}

推荐阅读