简体   繁体   English

JavaFX 动画定时器和事件

[英]JavaFX AnimationTimer and Events

I have an AnimationTimer, that I use as an infinite loop like this:我有一个 AnimationTimer,我将其用作这样的无限循环:

animator = new AnimationTimer(){
  @Override
  public void handle(long now) {
    // Update
    Game.simulationStep();
    // Render
    Game.render();
    }
  }
};
animator.start();

The handle function is called 60 times a second, updates a small Game and renders some views in a scenegraph.句柄 function 每秒调用 60 次,更新一个小游戏并在场景图中渲染一些视图。

What I´m asking myself is, if when I have Events like a button click, will the code of the event be executed after a loop iteration is done?我问自己的是,如果当我有像按钮点击这样的事件时,是否会在循环迭代完成后执行事件代码? Or is it multithreaded?还是它是多线程的?

The thing is, I have a List of GameObjects which can be manipulated by the event (removing GameObjects by button click) but also by the logic in simulationStep.问题是,我有一个游戏对象列表,可以通过事件(通过单击按钮删除游戏对象)进行操作,也可以通过模拟步骤中的逻辑进行操作。 It could be problematic, if the event removes GameObjects from that List, while simulationStep() is doing something with the Objects in the List.如果事件从该列表中删除游戏对象,而模拟步骤()正在对列表中的对象执行某些操作,则可能会出现问题。

AnimationTimer is not multithreaded and the handle() method runs on the JavaFX application thread , so I guess if you put an infinite loop or a blocking call inside handle() , it freezes the application. AnimationTimer不是多线程的,并且handle()方法在JavaFX 应用程序线程上运行,所以我猜如果你在handle()中放置无限循环或阻塞调用,它会冻结应用程序。 Answering your question, unless you have some behaviour that executes on other threads, it'll work fine.回答您的问题,除非您有在其他线程上执行的某些行为,否则它会正常工作。

Here's a related thread: Is AnimationTimer running in its own thread?这是一个相关的线程: AnimationTimer 是否在自己的线程中运行?

The answer depends not on the code you provide but on your other code.答案不取决于您提供的代码,而是取决于您的其他代码。

If the code is responding to events originating in the JavaFX framework (like a button press), then you don't need to worry, because those events are also on the JavaFX thread, the same as the animation timer.如果代码响应源自 JavaFX 框架的事件(如按下按钮),那么您不必担心,因为这些事件也在 JavaFX 线程上,与 Z6F1C25ED1523962F1BBF9DEE 相同。

You only need to worry if the event originates on a different thread outside of JavaFX.您只需要担心事件是否源自 JavaFX 之外的不同线程。 For example, an incoming chat message from a network chat client, or an AI loop that you are running on your own thread.例如,来自网络聊天客户端的传入聊天消息,或您在自己的线程上运行的 AI 循环。

Also, you shouldn't use property listeners and bindings that might change values on another thread.此外,您不应使用可能会更改另一个线程上的值的属性侦听器和绑定。 For example, don't modify from another thread an observable list that is used to back a list view.例如,不要从另一个线程修改用于支持列表视图的可观察列表。 The internal implementation of the observer and binding features assumes that the properties and listeners are all used on a single thread.观察者和绑定功能的内部实现假定属性和侦听器都在单个线程上使用。 Again, that is only something to worry about if your code is actually multi-threaded.同样,如果您的代码实际上是多线程的,那么这只是需要担心的事情。

If you do really have multi-threaded code with events originating from other threads, use JavaFX concurrency , eg Task and/or Platform.runLater .如果您确实有来自其他线程的事件的多线程代码,请使用JavaFX concurrency ,例如Task和/或Platform.runLater Possibly in conjunction with a queue as in Seph's answer as demonstrated (somewhat), by this multi-threaded JavaFX logging framework using a queue .这个多线程 JavaFX 日志框架使用 queue可能与Seph 的回答中的队列结合使用(在某种程度上)。 However, usually a separate queue is not required, because Platform.runLater will add runnables to a built-in queue that JavaFX maintains for stuff to be run on the JavaFX thread later.但是,通常不需要单独的队列,因为Platform.runLater会将可运行对象添加到 JavaFX 维护的内置队列中,以便稍后在 JavaFX 线程上运行。

For your specific concern:对于您的具体问题:

I have a List of GameObjects which can be manipulated by the event (removing GameObjects by button click) but also by the logic in simulationStep.我有一个游戏对象列表,可以通过事件(通过单击按钮删除游戏对象)以及模拟步骤中的逻辑进行操作。 It could be problematic, if the event removes GameObjects from that List, while simulationStep() is doing something with the Objects in the List.如果事件从该列表中删除游戏对象,而模拟步骤()正在对列表中的对象执行某些操作,则可能会出现问题。

No. It will not be problematic.不,不会有问题。 Everything is running on a single thread, the GameObjects cannot be removed by button click while simulationStep() is running, because the click handler and the simulationStep cannot be running at the same time.一切都在单个线程上运行,在simulationStep()运行时,不能通过按钮单击删除游戏对象,因为单击处理程序和simulationStep 不能同时运行。

A good summary of different options for executing periodic events and when and when not to involve multiple threads, plus how to handle them if they are used, is in Slaw's answer to: Slaw 对执行周期性事件的不同选项以及何时和何时不涉及多个线程以及如何处理它们进行了很好的总结:

I advise reading the JavaFX architecture overview sections on the Glass Windowing Toolkit, Threads, and Pulse (twice).我建议阅读Glass Windowing Toolkit、Threads 和 Pulse 上的 JavaFX 架构概述部分(两次)。 The document explains how the JavaFX system works with respect to threading, event processing, and pulse handling (the AnimationTimer handle method is triggered by a pulse).该文档解释了 JavaFX 系统如何在线程、事件处理和脉冲处理方面工作(AnimationTimer 处理方法由脉冲触发)。

You can add the events to a queue and process that queue first in your animation timer.您可以将事件添加到队列并首先在 animation 计时器中处理该队列。 This should avoid anytime of concurrency or race condition issues you may be concerned about without hurting anything if they do not actually exist.这应该可以避免任何时候您可能担心的并发或竞争条件问题,如果它们实际上不存在,则不会伤害任何东西。

animator = new AnimationTimer(){
  @Override
  public void handle(long now) {
    //Process
    Game.processEvents();
    // Update
    Game.simulationStep();
    // Render
    Game.render();
    }
  }
};
animator.start();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM