Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX中的多个独立阶段_Javafx - Fatal编程技术网

JavaFX中的多个独立阶段

JavaFX中的多个独立阶段,javafx,Javafx,有没有办法在JavaFX中启动多个独立的阶段?所谓独立,我的意思是所有阶段都是从主线程创建的 目前,我的应用程序或多或少是一种算法,我希望在执行过程中绘制一些图表,主要是检查结果是否正确/是否需要调试 问题是,我不知道如何独立地创建和显示多个阶段,也就是说,我想这样做 public static void main(){ double[] x = subfunction.dosomething(); PlotUtil.plot(x); //creates a new window

有没有办法在JavaFX中启动多个独立的阶段?所谓独立,我的意思是所有阶段都是从主线程创建的

目前,我的应用程序或多或少是一种算法,我希望在执行过程中绘制一些图表,主要是检查结果是否正确/是否需要调试

问题是,我不知道如何独立地创建和显示多个阶段,也就是说,我想这样做

public static void main(){
    double[] x = subfunction.dosomething();
    PlotUtil.plot(x); //creates a new window and shows some chart/table etc.
    double[] y = subfunction.dosomethingelse();
    PlotUtil.plot(y); //creates a new window and shows some chart/table etc.
    .....
}
这将允许使用PlotUtil,就像在其他脚本语言(如Matlab或R)中使用绘图函数一样

因此,主要问题是如何设计绘图工具?到目前为止,我尝试了两件事

PlotUtils对每个绘图调用使用Application.launch每次创建一个带有单个场景的新阶段->不能作为Application.launch调用一次。 在第一次调用PlotUtils期间创建某种主阶段,获取对已创建应用程序的引用并从中开始后续阶段->不作为使用Application.launchSomeClass.class工作我无法获取对已创建应用程序实例的引用。 什么样的结构/设计允许我实现这样的PlotUtils功能

更新1:

我提出了以下想法,并想知道在这个解决方案中是否有任何重大错误

所有绘图都要实现的接口

public abstract class QPMApplication implements StageCreator {
   @Override
   public abstract  Stage createStage();
}
打印功能:

public class PlotStage {
    public static boolean toolkitInialized = false;

    public static void plotStage(String title, QPMApplication stageCreator) {
        if (!toolkitInialized) {
            Thread appThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    Application.launch(InitApp.class);
                }
            });
            appThread.start();
        }

        while (!toolkitInialized) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                Stage stage = stageCreator.createStage();
                stage.show();
            }
        });
    }

    public static class InitApp extends Application {
        @Override
        public void start(final Stage primaryStage) {
            toolkitInialized = true;
        }
    }
}
使用它:

public class PlotStageTest {

    public static void main(String[] args) {

        QPMApplication qpm1 = new QPMApplication() {
            @Override
            public Stage createStage() {
                Stage stage = new Stage();
                StackPane root = new StackPane();
                Label label1 = new Label("Label1");
                root.getChildren().add(label1);
                Scene scene = new Scene(root, 300, 300);
                stage.setTitle("First Stage");
                stage.setScene(scene);
                return stage;
            }
        };

        PlotStage.plotStage(qpm1);

        QPMApplication qpm2 = new QPMApplication() {
            @Override
            public Stage createStage() {
                Stage stage = new Stage();
                StackPane root = new StackPane();
                Label label1 = new Label("Label2");
                root.getChildren().add(label1);
                Scene scene = new Scene(root, 300, 200);
                stage.setTitle("Second Stage");
                stage.setScene(scene);
                return stage;
            }
        };

        PlotStage.plotStage(qpm2);

        System.out.println("Done");

    }
}

这里最简单的方法就是重构应用程序,使其从FX应用程序线程驱动。例如,您可以将原始代码块重写为

public class Main extends Application {

    @Override
    public void start(Stage primaryStageIgnored) {
        double[] x = subfunction.dosomething();
        PlotUtil.plot(x); //creates a new window and shows some chart/table etc.
        double[] y = subfunction.dosomethingelse();
        PlotUtil.plot(y); //creates a new window and shows some chart/table etc.
        //  .....
    }

    public static void main(String[] args) {
        launch(args);
    }
}
现在PlotUtil.plot。。。仅仅是创造一个舞台,在其中放置一个场景,并展示它

这假设您正在调用的方法不阻塞,但如果阻塞,您只需将它们包装在任务中并调用PlotUtils.plot。。。在任务的onSucceeded处理程序中

如果您真的想从非JavaFX应用程序中实现这一点,那么有一种非常有名的方法,通过创建一个新的JFXPanel,强制JavaFX应用程序线程在尚未启动时启动。应在AWT事件调度线程上创建JFXPanel

这是第二种技术的一个非常基本的例子。启动应用程序并在控制台中键入show。键入exit以退出

import java.util.Scanner;
import java.util.concurrent.FutureTask;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import javax.swing.SwingUtilities;


public class Main {

    private JFXPanel jfxPanel ;

    public void run() throws Exception {
        boolean done = false ;
        try (Scanner scanner = new Scanner(System.in)) {
            while (! done) {
                System.out.println("Waiting for command...");
                String command = scanner.nextLine();
                System.out.println("Got command: "+command);
                switch (command.toLowerCase()) {
                case "exit": 
                    done = true;
                    break ;
                case "show":
                    showWindow();
                    break;
                default:
                    System.out.println("Unknown command: commands are \"show\" or \"exit\"");   
                }
            }
            Platform.exit();
        }
    }

    private void showWindow() throws Exception {
        ensureFXApplicationThreadRunning();
        Platform.runLater(this::_showWindow);
    }

    private void _showWindow() {
        Stage stage = new Stage();
        Button button = new Button("OK");
        button.setOnAction(e -> stage.hide());
        Scene scene = new Scene(new StackPane(button), 350, 75);
        stage.setScene(scene);
        stage.show();
        stage.toFront();
    }

    private void ensureFXApplicationThreadRunning() throws Exception {

        if (jfxPanel != null) return ;

        FutureTask<JFXPanel> fxThreadStarter = new FutureTask<>(() -> {
            return new JFXPanel();
        });
        SwingUtilities.invokeLater(fxThreadStarter);
        jfxPanel = fxThreadStarter.get();
    }

    public static void main(String[] args) throws Exception {
        Platform.setImplicitExit(false);
        System.out.println("Starting Main....");
        new Main().run();
    }

}

这里最简单的方法就是重构应用程序,使其从FX应用程序线程驱动。例如,您可以将原始代码块重写为

public class Main extends Application {

    @Override
    public void start(Stage primaryStageIgnored) {
        double[] x = subfunction.dosomething();
        PlotUtil.plot(x); //creates a new window and shows some chart/table etc.
        double[] y = subfunction.dosomethingelse();
        PlotUtil.plot(y); //creates a new window and shows some chart/table etc.
        //  .....
    }

    public static void main(String[] args) {
        launch(args);
    }
}
现在PlotUtil.plot。。。仅仅是创造一个舞台,在其中放置一个场景,并展示它

这假设您正在调用的方法不阻塞,但如果阻塞,您只需将它们包装在任务中并调用PlotUtils.plot。。。在任务的onSucceeded处理程序中

如果您真的想从非JavaFX应用程序中实现这一点,那么有一种非常有名的方法,通过创建一个新的JFXPanel,强制JavaFX应用程序线程在尚未启动时启动。应在AWT事件调度线程上创建JFXPanel

这是第二种技术的一个非常基本的例子。启动应用程序并在控制台中键入show。键入exit以退出

import java.util.Scanner;
import java.util.concurrent.FutureTask;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import javax.swing.SwingUtilities;


public class Main {

    private JFXPanel jfxPanel ;

    public void run() throws Exception {
        boolean done = false ;
        try (Scanner scanner = new Scanner(System.in)) {
            while (! done) {
                System.out.println("Waiting for command...");
                String command = scanner.nextLine();
                System.out.println("Got command: "+command);
                switch (command.toLowerCase()) {
                case "exit": 
                    done = true;
                    break ;
                case "show":
                    showWindow();
                    break;
                default:
                    System.out.println("Unknown command: commands are \"show\" or \"exit\"");   
                }
            }
            Platform.exit();
        }
    }

    private void showWindow() throws Exception {
        ensureFXApplicationThreadRunning();
        Platform.runLater(this::_showWindow);
    }

    private void _showWindow() {
        Stage stage = new Stage();
        Button button = new Button("OK");
        button.setOnAction(e -> stage.hide());
        Scene scene = new Scene(new StackPane(button), 350, 75);
        stage.setScene(scene);
        stage.show();
        stage.toFront();
    }

    private void ensureFXApplicationThreadRunning() throws Exception {

        if (jfxPanel != null) return ;

        FutureTask<JFXPanel> fxThreadStarter = new FutureTask<>(() -> {
            return new JFXPanel();
        });
        SwingUtilities.invokeLater(fxThreadStarter);
        jfxPanel = fxThreadStarter.get();
    }

    public static void main(String[] args) throws Exception {
        Platform.setImplicitExit(false);
        System.out.println("Starting Main....");
        new Main().run();
    }

}

只需创建多个阶段实例,并对其进行呼叫显示。感谢您的反馈。但我仍然必须确保1。该工具包已初始化,并在2。在fx线程而不是主线程上创建阶段。我相应地更新了帖子,非常感谢您的进一步建议。我想我不了解您的整个应用程序生命周期。如果我从头开始编写R接口,我的应用程序将启动。。。方法将显示一个控制台并在主阶段中显示它。当用户输入命令时,它将在事件处理程序中处理该命令,并输出到同一控制台,或者如果需要显示图形,例如,创建一个新阶段来显示该图形。你能这样组织它吗?如果是这样的话,那就很简单了。你当然是对的,但我的用例略有不同。首先,也许是最重要的一点,我不希望controlflow由JavaFX应用程序启动/驱动。我一直在寻找的是一种快速且有希望的、不太脏的方法,可以随时绘制一些图形,而不是像您在R/Matlab脚本中那样,在调试/开发过程中绘制一些中间结果,而不必担心工具包被初始化,确保在JavaFX线程上绘制等等。。。无论如何,我真的很感激你的评论。我很难理解为什么你不使用JavaFX应用程序来驱动它,即使该应用程序没有做任何其他事情:毕竟,你必须用一些东西来驱动它。但是如果你真的不能做到这一点,强迫JavaFX应用程序启动(如果它还没有启动)的快速方法是在AWT事件调度线程上创建一个JFXPanel。只需创建多个阶段实例并调用show就可以了。谢谢你的反馈。但我仍然必须确保1。工具箱
已初始化,为2。在fx线程而不是主线程上创建阶段。我相应地更新了帖子,非常感谢您的进一步建议。我想我不了解您的整个应用程序生命周期。如果我从头开始编写R接口,我的应用程序将启动。。。方法将显示一个控制台并在主阶段中显示它。当用户输入命令时,它将在事件处理程序中处理该命令,并输出到同一控制台,或者如果需要显示图形,例如,创建一个新阶段来显示该图形。你能这样组织它吗?如果是这样的话,那就很简单了。你当然是对的,但我的用例略有不同。首先,也许是最重要的一点,我不希望controlflow由JavaFX应用程序启动/驱动。我一直在寻找的是一种快速且有希望的、不太脏的方法,可以随时绘制一些图形,而不是像您在R/Matlab脚本中那样,在调试/开发过程中绘制一些中间结果,而不必担心工具包被初始化,确保在JavaFX线程上绘制等等。。。无论如何,我真的很感激你的评论。我很难理解为什么你不使用JavaFX应用程序来驱动它,即使该应用程序没有做任何其他事情:毕竟,你必须用一些东西来驱动它。但是如果您真的不能这样做,那么强制JavaFX应用程序启动(如果尚未启动)的快速方法是在AWT事件调度线程上创建一个JFXPanel。