无法通过另一个控制器控制另一个fxml文件的元素

时间:2019-06-07 15:41:13

标签: javafx javafx-8

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

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

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

点击按钮后,进度指示器将变为活动状态。

下面是代码:

Button.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>

ButtonController.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();
            }
        }

    }


}

ProgressIndicator.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 acces 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的第一条评论中所述的原因,进度指示器未更新。因此,我为我的应用程序创建了一个separte线程,由于进度指示器已按预期进行更新,因此似乎工作正常。

成功更新进度指示器的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:END

编辑2:开始

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

Main.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 Project

编辑2:结束

编辑3:开始

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

编辑3:END

1 个答案:

答案 0 :(得分:1)

我假设您想要这样的东西(请注意注释):

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();
    }
}