JavaFX 属性在 GUI 视图范围之外的可用性 [英] Usability of JavaFX Properties outside the scope of the GUI view

查看:17
本文介绍了JavaFX 属性在 GUI 视图范围之外的可用性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用 JavaFX (Java8) 工作一段时间后,我发现了 属性 非常有用,允许使用 bean 兼容变量绑定到使用计算树更新更改,例如:

After working some while with JavaFX (Java8) I had found the concept of Properties very useful, allowing to use bean compliant variables to be bound to update on changes using a calculation tree e.g.:

class Person {
    StringProperty name;
    ...
}

<小时>

Person owner;
Person human;

owner.name().bind(human.name());

这允许将 GUI 控件绑定到模型",以在更改时自动更新.

That allows to bind the GUI controls to the 'model', to automatically update on change.

所以我也开始使用Property 模型中的类(我的数据对象我正在执行我的功能操作).但是 JavaFX 是单线程 GUI 实现,如果在 JavaFX 线程中完成,则只允许设置链接到某些 GUI 控件的此类属性.否则会抛出异常:

So I also started to use the Property<T> class in the model (my data objects I am doing my functional operations). But the JavaFX is a single threaded GUI implementation and setting such a Property linked to some GUI controls is only allowed, if it is done in the JavaFX thread. Else an exception will be thrown:

  Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5

如果我现在开始编写多线程代码,我最终无法使用这些属性,即使我很想使用.我无法将所有更改封装在 Platform.runLater() 调用中以将其传递给 JavaFX 线程.

If I now start to write multithreaded code, I finally cannot use these Properties, even if I would love to. I cannot afford to encapsulate every change in a Platform.runLater() call to pass it to the JavaFX thread.

为什么 JavaFX 不提供线程安全的属性绑定?(或者是吗?)

Why does JavaFX not provide a thread-safe Property-Binding? (Or does it?)

推荐答案

JavaFX 属性在 GUI 视图范围之外的可用性

Usability of JavaFX Properties outside the scope of the GUI view

JavaFX 属性绝对可以在 GUI 视图范围之外使用.基本的 Oracle JavaFX 绑定教程演示了这一点通过创建一个简单的非 GUI Java 程序,该程序表示一个 Bill 对象,其中通过 JavaFX 属性公开了帐单的总金额.

JavaFX properties can definitely be used outside the scope of the GUI view. The basic Oracle JavaFX binding tutorial demonstrates this by creating a simple non-GUI java program which represents a Bill object where the total amount of the bill is exposed via a JavaFX property.

为什么 JavaFX 不提供线程安全的属性绑定?(或者是吗?)

Why does JavaFX not provide a thread-safe Property-Binding? (Or does it?)

JavaFX 不支持线程安全的属性绑定.它不支持线程安全属性绑定的原因可能是因为它不需要.

JavaFX does not support thread-safe property-binding. Probably the reason it does not support thread-safe property binding is because it does not need to.

虽然 JavaFX 内部有一个多线程架构,带有渲染线程、应用线程等,但在外部对开发人员来说,它实际上只暴露了单个应用线程.从开发人员的角度来看,开发人员将他们的应用程序编码为一个单线程系统.开发人员和内部 JavaFX 实现可以假设一切都在单线程环境中运行并且编码要简单得多(参见 多线程工具包:一个失败的梦想?如何在实际不同的线程中运行两个 JavaFX UI 以了解有关为什么这是案件).属性实现,知道它是在这样的环境中执行,也可以假设一个单线程架构,并跳过潜在的复杂的内置线程安全控制.

Although JavaFX internally has a multi-threaded architecture with a render thread, an application thread, etc., externally to developers it really only exposes the single application thread. From a developer point of view, the developer codes their application as a single threaded system. The developer and the internal JavaFX implementations can just assume that everything is running in a single-threaded environment and coding is much simpler (see Multithreaded toolkits: A failed dream? and How to run two JavaFX UI in actual different threads for some background information on why this is the case). The property implementation, knowing that it is executing in such an environment, can also assume a single threaded architecture and skip potentially complicating in-built thread safety controls.

JavaFX 确实能够为 并发生成新线程任务(也可以使用用于标准 Java 开发的许多并发工具中的任何一个).JavaFX 并发 API 确实能够以线程安全的方式反馈属性值(例如任务执行完成的工作百分比),但这是以非常特定的方式完成的.任务 API 具有用于修改此类属性的专门方法(例如 updateProgress) 并在内部使用线程检查和调用,例如 Platform.runLater 确保代码在线程中执行- 安全的方式.

JavaFX does have the ability to spawn new threads for concurrent tasks (and any of the many concurrent facilities for standard Java development can also be used). The JavaFX concurrent API does have the ability to feed back property values (such as percentage of work done for task execution) in a thread safe manner, but that is done in a very specific way. The task API has specialized methods for modifying such properties (for example updateProgress) and internally it uses thread checks and calls such as Platform.runLater to ensure that code executes in a thread-safe manner.

因此,JavaFX 并发实用程序不是通过 JavaFX 属性机制的内置功能来实现线程安全的,而是通过并发实用程序实现内部对非常具体且有限的一组属性进行显式检查和调用来实现线程安全的.即便如此,用户在使用这些实用程序时也必须非常小心,因为他们通常认为他们可以直接从并发任务中修改 JavaFX GUI 阶段属性(即使文档指出不应该这样做);如果使用标准 Java 并发实用程序(如 java.util.concurrent 包而不是 javafx.concurrent 包),则需要采取同样的措施.

So the JavaFX concurrency utilities don't achieve thread safety through in-built capabilities of the JavaFX property mechanism, but instead through explicit checks and calls inside the concurrency utility implementation for a very specific and limited set of properties. Even then, users have to be very careful when using these utilities as they often assume they can do things such as modify JavaFX GUI stage properties directly from within their concurrent tasks (even though documentation states that this should not be done); the same care needs to be taken if standard Java concurrent utilities like the java.util.concurrent package is used rather than javafx.concurrent.

有人可能会创建 JavaFX 属性机制的扩展,以便在线程安全环境中表现得更好,但迄今为止还没有人创建过这样的扩展.

It is possible that somebody could create an extension to the JavaFX property mechanism to better behave in thread safe environment, but nobody has created such an extension to date.

但是 JavaFX 是单线程 GUI 实现,并且只有在 JavaFX 线程中完成时,才允许设置链接到某些 GUI 控件的此类属性.

But the JavaFX is a single threaded GUI implementation and setting such a property linked to some GUI controls is only allowed, if it is done in the JavaFX thread.

问题的标题是JavaFX 属性在 GUI 视图范围之外的可用性",但您描述的特定问题是此问题的一个非常具体的子集,我认为您有以下组合:

The title of the question is "Usability of JavaFX properties outside the scope of the GUI view", but the particular issue you describe is a pretty specific subset of this, where I think you have the following combination of things:

  1. 模型类的属性.
  2. 模型类中的属性可由 JavaFX 应用程序线程或其他用户线程读取和写入.
  3. 模型类中的属性可以绑定到活动的 GUI 元素,例如 TextField 中的文本或屏幕上显示的标签.

开箱即用,这是行不通的,因为 JavaFX 系统假定 JavaFX GUI 组件的属性只能在 JavaFX 应用程序线程上读取或修改.此外,为了在内部支持绑定和更改侦听器,属性本身需要维护要修改的侦听器和绑定属性列表,并且这些列表可能假定它们只能从单个线程访问或修改.您也许可以通过使用 Platform.runLater 包装调用来确保每次读取或写入都在单个线程上进行来解决此问题,以将调用放置在 JavaFX 应用程序线程上,但从您的问题来看,这正是您试图避免的代码类型.

Out of the box this isn't going to work because the JavaFX system assumes that properties of JavaFX GUI components are only read or modified on the JavaFX application thread. Also, internally to support binding and change listeners, the properties themselves need to maintain lists of listeners and bound properties to modify, and these lists likely assume that they will only be accessed or modified from a single thread. You can perhaps work around this by ensuring that every read or write goes on a single thread by wrapping invocations using Platform.runLater to place the call on the JavaFX application thread, but from your question, this is exactly the kind of code which you are trying to avoid.

IMO 对于我在上面几点中概述的用例,没有其他解决方案并且必须使用 Platform.runLater 包装.通过提供属性访问和更新的外观方法(类似于 JavaFX 并发任务实现),您可以潜在地隐藏 runLater 调用的一些复杂性和样板文件,但是这样的系统实现起来可能有点复杂(特别是如果您想要实现整个属性/绑定子系统的通用解决方案,而不是像 Task 那样针对几个特定属性的专门解决方案).

IMO for the use case I outlined in the points above, there is no other solution and Platform.runLater wrapping must be used. You can potentially hide some of the complexity and boilerplate for the runLater calls by providing facade methods for property access and updates (similar to the JavaFX concurrent Task implementation), but such a system is likely a bit complex to implement (especially if you want to achieve a generic solution for the entire property/binding subsystem, rather than a specialized solution for a couple of specific properties like Task has).

JavaFX 属性有什么用?

现有的主要用例是为 JavaFX GUI 应用程序支持基于绑定的 GUI 编程模型.JavaFX 属性广泛用于 JavaFX API 和使用该 API 的任何应用程序.

The primary existing use-case is for supporting the binding-based GUI programming model for JavaFX GUI applications. JavaFX properties are used extensively with the JavaFX API and any application which uses that API.

由于 JavaFX 现在包含在所有标准的新 Oracle JDK 发行版中,您还可以使用来自非 JavaFX 程序的属性.例如,在 JPA 实体 bean 中有关于如何使用这些属性的讨论.根据我的经验,这些非 JavaFX API 用例目前非常罕见.

As JavaFX is now included in all standard new Oracle JDK distributions, you can also use the properties from non-JavaFX programs. For instance, there are discussions on how to use these properties in JPA entity beans for instance. These non-JavaFX API use-cases are currently pretty rare in my experience.

尽管 JavaFX 属性和绑定包在 javafx 包命名空间内,但它们不依赖于其他 JavaFX 包.在未来的模块化 JDK(例如 Java 9)中,有可能让 Java 程序依赖于 JavaFX 属性和绑定模块,而不依赖于其他用于 JavaFX GUI 开发的模块(这可能对 JavaFX GUI 开发有用)某些无头服务器系统,这是许多 Java 应用程序的主要部署目标).

Although the JavaFX properties and binding packages are within the javafx package namespace, they do not depend on other JavaFX packages. In a future modular JDK, such as Java 9 is proposed to be, it would be possible to have a Java program depend on a JavaFX property and binding module and not have any dependency on other modules for JavaFX GUI development (which might be useful for certain headless server systems, which are the primary deployment target for many Java applications).

最初为其他 JavaFX 工具(例如时间线和转换)设置了类似的设计,以便通过时间线基于时间调度任务的实时 Java 系统可以使用来自 JavaFX 的动画/时间线模块,而无需依赖剩下的交给 JavaFX 系统(但我不确定原始设计是否一直延续到今天,所以这可能不再可能了,动画模块的基本脉冲通常被锁定在 60fps 的最小滴答上,可能锁定在屏幕刷新率取决于实现).

A similar design was originally setup for other JavaFX facilities such as the timelines and transitions, such that a real-time Java system with time based scheduling of tasks via Timelines could make use of an animation/timeline module from JavaFX without depending upon the rest to the JavaFX system (but I am not sure that original design was carried through to today, so that might not really be possible anymore and the base pulse of the animation module is usually keyed to the minimum tick of 60fps perhaps locked at a screen refresh rate depending on the implementation).

JavaFX 属性不是 Java 属性管理的通用解决方案,但它们可能是迄今为止我所见过的此类解决方案的最接近、最完整的实现.理想情况(正如我记得 JavaFX 项目负责人 Richard Bair 所说的那样),属性功​​能将内置到 Java 编程语言中,因此支持不仅来自 API,还来自改进的语言语法.也许一些未来的 Java 版本,比如 10+ 可能会有这样的设施.当然,这是一个古老的讨论,可能可以追溯到 Java 语言和 JDK 规范的开始.尽管如此,世界并不理想,JavaFX 属性机制(即使它的语法有点庞大且缺乏对线程安全的内置支持),仍然是许多应用程序的有用工具.另请注意,通过 ScalaFX 对其他语言(如 Scala)进行了扩展,这使得 JavaFX 属性机制看起来像是该语言语法的一部分.

JavaFX properties are not the generic solution to property management for Java, but they are probably the closest, most complete implementation of such a solution that I have seen so far. The ideal (as I recall the JavaFX project lead Richard Bair stating), is that property functionality would be built into the Java programming language, so the support comes not only from an API, but from improved language syntax. Perhaps some future Java version such as 10+ might have facilities such as these. Of course, that is an old discussion probably dating back to the beginning of the Java language and JDK specifications. Still, the world is not ideal and the JavaFX property mechanism (even with it's kind of bulky syntax and lack of in-built support for thread-safety), is still a useful tool for many applications. Also note that there are extensions for other languages as as Scala via ScalaFX which make the JavaFX property mechanism seem like it part of the syntax for that language.

EasyBind 等第三方库,增强了 JavaFX 属性机制以更好地支持编程范式,例如函数式反应式编程.

Third Party libraries such as EasyBind, enhance the JavaFX property mechanism to better support programming paradigms such as functional reactive programming.

现在,如果我想在 JavaFX 程序中广泛使用属性类型工具,我可能会基于 JavaFX 属性和(可能的)EasyBind 和 ReactFX,因为这似乎是 Java 的最佳解决方案.

For now, if I wanted to make extensive use of property type facilities in a JavaFX program, I would probably base it on a combination of JavaFX properties and (potentially) EasyBind and ReactFX, as that seems to be the best solution for Java.

我不会在高度并发的环境中使用这样的解决方案,在这种环境中,由于底层库中缺乏线程安全支持,线程是非隔离的.属性基于对可变对象的副作用更改,这在多线程程序中很难推理.即使修改了内部属性实现以允许对属性进行线程安全的读/写,我也不确定这是否是一种很好的方法.对于需要在并发子任务之间进行大量通信的高并发系统,使用另一种编程范式,例如 Actors (例如 akka/erlang) 或 通信顺序过程 可能比绑定属性更合适.

I would not use such a solution in a highly concurrent environment where threading is non-compartmentalized due to the lack of thread-safety support in the underlying libraries. Properties are based upon side-effect changes to mutable objects, which is a pretty difficult thing to reason about in multi-threaded programs. Even if the internal property implementation was modified to allow thread-safe read/writes on properties, I'm not sure that it would be such a great approach. For highly concurrent systems requiring a lot of communication between concurrent subtasks, use of another programming paradigm such as Actors (e.g. akka/erlang) or communicating sequential processes may be more appropriate than bound properties.

这篇关于JavaFX 属性在 GUI 视图范围之外的可用性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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