我正在编写一个JavaFX应用程序,它可以在套接字上接收数据点并实时显示它们。问题是JavaFX渲染速度太慢。我有一个Swing实现,运行速度够快,但我需要使用JavaFX。我应该使用什么方法来处理JavaFX Canvas多线程?
,我中工作的制约因素有:
- 为可视化的控制只能通过JavaFX应用程序线程(我相信这是必需的所有JavaFX和Swing应用程序)进行更新。
- 可视化应该从人眼的角度来平滑地更新。每秒大约10次更新就足够了。每秒一次都不够。
- 传入的数据速率足够高(每秒大约50个事件,在其他上下文中并不高),并且每个事件处理都足够昂贵,以至于必须在JavaFX应用程序以外的线程中接收和处理传入数据线程,以便GUI不会阻塞(我相信对于许多GUI应用程序来说这是一种常见的需求)。
到目前为止,我的方法是使用Canvas JavaFX节点作为可视化控件,接收线程调度Canvas的更新以稍后在JavaFX应用程序线程中运行,就像这样。
public void onEvent(Event event) {
....do processing...
Platform.runLater(new Runnable() {
@Override
public void run() {
graphics.setFill(...);
graphics.fillRect(...);
}});
}
我想到了几个办法,可能加快这的:
- 使用WritableImage而不是为可视化的画布。缺点是WritableImage/PixelWriter似乎没有很多绘图方法,例如它甚至没有fillRect。我想我将不得不实施我自己的版本,我的版本可能会变慢。
- 让Canvas对象拥有处理传入数据的线程。从该画布复制到作为JavaFX应用程序线程场景图形中节点的画布。该副本可能会沿着这些行的代码
sceneCanvas.getGraphicsContext2D().drawImage(processingCanvas.snapshot(SnapshotParameters(), null) 0, 0);
完成。这样做的缺点是我认为它不是线程安全的,并且快照调用似乎相对昂贵。 - 渲染到处理传入数据的线程中的AWT BufferedImage,然后使用SwingFXUtils.toFXImage()从BufferedImage复制到画布。这样做的缺点是线程语义看起来不太清楚,使用AWT看起来有点愚蠢。
你能提出一些潜在的方法吗?
谢谢!
您可以在处理线程中创建FX画布,然后将其交给FX应用程序线程(通过Platform.runLater)以交换场景图中的“旧”画布。 – isnot2bad 2014-09-29 09:57:48
您是否已经测量了您的画布绘制方法运行的时间? – isnot2bad 2014-09-29 09:58:47
绘图方法相对较快,通常少于一毫秒。我发现最大的问题是代码使用了Platform.runLater()。增加每个Platform.runLater()调用中完成的工作可显着提高应用程序的吞吐量。我不确定这个问题是否是Platform.runLater()的开销,或者问题是JavaFX是否将脉冲调用与Platform.runLater()调用交错,从而导致更多的重绘。我仍然很好奇人们认为对于这样的应用来说,这是一个很好的架构方法。谢谢! – 2014-09-29 18:41:37