我今天才开始学习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();
}
我觉得我没有真正理解在这里做什么是最好的,而我试图做的可能是黑客。对于我应该做什么,或者如何解决这个问题,有什么建议吗?
JavaFX中线程的基本规则(请原谅,如果您已经理解了其中的一些,我只想完整介绍一下)是:
Node
(场景图的一部分)状态的东西都应该在FX应用程序线程上执行为了帮助实现这些目标,JavaFXAPI提供了一个任务
类。它有一个call()
方法返回一个值;它是一个可运行的
,因此可以作为参数提供给线程
构造函数,或者传递给执行器
。它还提供了保证在FX应用程序线程上执行的有用回调,例如setonsucceed
,setOnFailed
,以及各种更新。。。()
更新属性的方法,例如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