JavaFX任务结束和JavaFX线程 [英] JavaFX Task ending and JavaFX threading

查看:156
本文介绍了JavaFX任务结束和JavaFX线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天才开始学习JavaFX,我试图通过制作Snake克隆来了解更多信息,但我遇到了线程问题。我想创建一个更新蛇在屏幕上的位置的线程,但不能以正常的Runnable线程方式使用它,因为我在该线程中使用JavaFX更新绘制到屏幕的矩形位置(我学到了你不能这样做,而且必须改为使用Tasks,Services,Platform.runLater等?)我创建线程的类扩展了JavaFX.scene.layout.Pane,我试图用一个任务来更新蛇的位置。我的问题是:任务似乎只运行一次或两次并退出,没有我给出任何中断。

I only just started learning about JavaFX today and I was trying to learn more about it by making a Snake clone, but I am having trouble with threading. I wanted to create a thread that updated the snake's position on the screen, but couldn't use one in a normal Runnable thread way, because I was using JavaFX from within that thread to update positions of rectangles drawn to the screen (Which I learned you cannot do, and must instead use Tasks, Services, Platform.runLater, etc?) My class that I was creating the thread from extends JavaFX.scene.layout.Pane, and I am trying to use a task to update the snake position. My problem is: The task only seems to run once or twice and quits, without me giving any interrupts.

扩展Pane的类的构造函数(The Snake类扩展Group ):

Constructor for the class that extends Pane (The Snake class extends Group):

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

我觉得我实际上并没有抓住这里最好的事情是的,我想做的可能是hackish。有什么建议我应该做什么,或者我如何解决这个问题?

I feel like I don't actually grasp what the best thing to do here is, and what I am trying to do may be hackish. Are there any suggestions on what I should do, or how I could fix this?

推荐答案

JavaFX中线程的基本规则(原谅我,如果你已经理解其中一些,我只想完成)是:

The basic rules for threading in JavaFX (and forgive me if you already understand some of this, I just want to be complete) are:


  1. 阻止执行的任何事情(或者执行的时间很长)应该在后台线程上运行 - 而不是在FX应用程序线程上运行

  2. 任何改变节点那是场景图的一部分应该在FX应用程序线程上执行

  1. Anything that blocks execution (or takes a long time to execute) should be run on a background thread - not on the FX Application Thread
  2. Anything that changes the state of a Node that is part of the scene graph should be executed on the FX Application Thread

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

In order to help achieve these, the JavaFX API provides a Task class. This has a call() method that returns a value; it is a Runnable so can be provided as the argument to a Thread constructor, or passed to an Executor. It also provides useful callbacks that are guaranteed to be executed on the FX Application Thread, such as setOnSucceeded, setOnFailed, and various update...() methods that update properties such as progress and message on the FX Application Thread.

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

However, the Task class is really designed for one-off tasks: think about applications that need to retrieve data from a database, for example, which may take time. These execute a specific action and return a result. Your case is somewhat different, in that your thread is executing continuously.

在这种情况下,最好使用一个简单的 Thread 并使用 Platform.runLater(...)更新UI。 Platform.runLater(...)获取 Runnable 并执行其 run() FX应用程序线程上的方法。

In this case, it's probably better to use a simple Thread and use Platform.runLater(...) to update the UI. Platform.runLater(...) takes a Runnable and executes its run() method on the FX Application Thread.

我不清楚为什么你的代码表现得像你描述的那样,但假设方法调用 snake.updatePosition()导致UI发生变化,应该在FX Application Thread上执行。在任何情况下我都会尝试

It's not clear to me why your code is behaving the way you describe, but assuming the method call snake.updatePosition() causes a change in the UI, that should be executed on the FX Application Thread. In any case I would try

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替换匿名内部类会更好看:

If you are using Java 8, this all looks a lot nicer with lambdas replacing the anonymous inner classes:

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

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

One other technique in JavaFX for executing something periodically is to (ab?)use an Animation:

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

或者,在Java 8中,有点光滑

or, in Java 8, the somewhat slick

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
        event -> snake.updatePosition()));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

这篇关于JavaFX任务结束和JavaFX线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆