当前位置: 首页 > 知识库问答 >
问题:

JavaFX任务结束和JavaFX线程

饶高雅
2023-03-14

我今天才开始学习JavaFX,我试图通过制作一个Snake克隆来了解更多,但是我在线程方面遇到了麻烦。我想创建一个线程来更新蛇在屏幕上的位置,但是不能以正常的Runnable线程方式使用它,因为我在线程中使用JavaFX来更新绘制到屏幕上的矩形的位置(我知道你不能这样做,必须使用任务,服务,Platform.run稍后,等等?)我创建线程的类扩展了JavaFX。scene.layout.窗格,我试图使用一个任务来更新蛇的位置。我的问题是:这个任务似乎只运行一两次就退出了,我没有中断。

扩展窗格的类(The Snake类扩展组)的构造函数:

public GameFrame(){
    this.setPrefSize(800, 600);

    Snake snake = new Snake();
    this.getChildren().add(snake);

    taskThread = new Thread(new Task<Void>() { 
        protected Void call() throws Exception {
                while(!Thread.currentThread().isInterrupted()){
                    snake.updatePosition();
                    try{
                    Thread.sleep(1000);
                    } catch(InterruptedException e){
                        break;
                    }
                }
            return null;
        }
    });
    taskThread.start();
}

我觉得我没有真正理解在这里做什么是最好的,而我试图做的可能是黑客。对于我应该做什么,或者如何解决这个问题,有什么建议吗?

共有1个答案

郜光明
2023-03-14

JavaFX中线程的基本规则(请原谅,如果您已经理解了其中的一些,我只想完整介绍一下)是:

  1. 任何阻止执行(或需要很长时间才能执行)的东西都应该在后台线程上运行-而不是在FX应用程序线程上
  2. 任何改变Node(场景图的一部分)状态的东西都应该在FX应用程序线程上执行

为了帮助实现这些目标,JavaFXAPI提供了一个任务类。它有一个call()方法返回一个值;它是一个可运行的,因此可以作为参数提供给线程构造函数,或者传递给执行器。它还提供了保证在FX应用程序线程上执行的有用回调,例如setonsucceedsetOnFailed,以及各种更新。。。()更新属性的方法,例如FX应用程序线程上的进度消息

然而,Task类实际上是为一次性任务设计的:例如,考虑需要从数据库检索数据的应用程序,这可能需要时间。它们执行特定的操作并返回结果。您的情况有所不同,因为您的线程正在持续执行。

在这种情况下,最好使用一个简单的Thread并使用Platform.run稍后(...)来更新用户界面。Platform.run稍后(...)需要一个Runnable并在FX Application Thread上执行其run()方法。

我不清楚为什么您的代码按照您描述的方式运行,但假设方法调用snake。updatePosition()会导致用户界面发生变化,该变化应在FX应用程序线程上执行。无论如何,我会试试看

taskThread = new Thread(new Runnable() { 
    public void run() {
            while(!Thread.currentThread().isInterrupted()){
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        snake.updatePosition();
                    }
                });
                try{
                    Thread.sleep(1000);
                } catch(InterruptedException e){
                    break;
                }
            }
    }
});

如果您使用的是Java 8,那么使用lambdas替换匿名内部类时,这一切看起来会更好:

taskThread = new Thread( () -> {
    while (! Thread.currentThread().isInterrupted()) {
        Platform.runLater( snake::updatePosition );
        try {
            Thread.sleep(1000);
        } catch (InterruptedException exc) {
            break ;
        }
    }
});

JavaFX中定期执行某件事情的另一种技术是(ab?)使用动画:

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
        new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                snake.updatePosition();
            }
        }
    ));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

或者,在Java8中,有点圆滑的

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
        event -> snake.updatePosition()));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();
 类似资料:
  • 我是JavaFx/并发的新手,所以我在JavaFX中阅读了并发教程,但是我仍然对JavaFX Gui中后台线程的实现有点困惑。 我试图编写一个与一些串行设备(使用JSSC-2.8)接口的小图形用户界面,并根据这些设备的响应更新图形用户界面。但是,在写入消息和设备响应之间有一个延迟,在任意的时间内使用Thread.sleep()对我来说不是一个可靠的编程方式。因此,我想使用并发包中的等待()和通知(

  • 我正在编写一个JavaFX应用程序,我的对象扩展任务提供了JavaFXGUI线程之外的并发性。 我的主要课程是这样的: 我的GUI控制器示例如下(略作抽象): 目前,我的任务只是进行睡眠并打印数字1到10: 我遇到的问题是,一旦任务完成,就好像启动任务的线程继续运行一样。因此,当我按下右上角的“X”退出JavaFX应用程序时,JVM继续运行,我的应用程序不会终止。如果你看一下我的主课,我已经把系统

  • 问题内容: 我在执行后台任务时使JavaFX UI保持活动状态时遇到问题。我已经设置了这个非常简单的代码- 我希望发生的事情是让进度条每1秒钟更新一次,直到任务完成。而是,UI完全冻结10秒钟,之后进度条显示为完成。明确地说- 问题不仅在于所有更新最终一次出现,而且UI直到那时都完全没有响应。 我已经阅读了有关此主题的其他任何问题,但找不到答案。我究竟做错了什么? 谢谢。 问题答案: 使用 sta

  • 问题内容: 我对JavaFX中的/ 概念非常困惑。 我在后台工作中使用了基于后台线程的模型,该模型要求对UI进行任何更新。 假设我对进度栏等不感兴趣。我正在对模型进行一些实际工作,这些工作必须在GUI的视图中进行更新(例如,根据后台的某些连接随时间更新的参与者列表,基于某些用户输入的参与者列表,按年龄分类)和起源)。这是我通常在启动并使用的后台线程中实现的。 现在,在JavaFX 2中,它们使用s

  • 我正在使用JavaFX呈现一些SVG内容。我定义了许多方法,返回不同SVG形状(椭圆、圆、矩形、直线等)的路径。它们似乎都管用,除了线条法。JavaFX不会返回错误(意味着路径可能是正确的),但它也不会画出任何东西。这里是我的方法。 方法根据返回或,返回或。 下面是一个示例方法调用: 在我看来是有效的,但什么也没有画出来...

  • 我正在构建一个多屏幕JavaFX应用程序,数据从SQL数据库拉到ObservableList,并通过Tableview显示在界面上。由于应用程序的多屏幕特性,我试图通过控制器将数据从ObservableList初始化到Tableview。SQL拉入ObservableList是通过新线程上的任务完成的。当我包含sqlCSEditTbl时。itemsProperty()。setValue((Obse