我使用运行 Windows 的 Microsoft Surface Book 2 笔记本电脑在 Java/JavaFX 16 上获取触摸事件。
样本来源
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.TouchEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class TouchTest extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
System.out.println("java.version: " + System.getProperty("java.version"));
System.out.println("javafx.runtime.version: " + System.getProperties().get("javafx.runtime.version"));
Scene scene = new Scene(new Pane(), 800, 800);
scene.addEventFilter(TouchEvent.ANY, System.out::println);
stage.setScene(scene);
stage.show();
}
}
执行指令
使用 Java 16 和 JavaFX 16,运行示例程序并触摸显示的空窗格(通过用手指触摸触摸屏,而不是使用触控板并按下它)。
程序输出
C:\Users\send2\.jdks\temurin-16.0.2\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3.2\lib\idea_rt.jar=56576:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\send2\.m2\repository\org\openjfx\javafx-controls\16\javafx-controls-16.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-graphics\16\javafx-graphics-16.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-base\16\javafx-base-16.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-fxml\16\javafx-fxml-16.jar -p C:\Users\send2\.m2\repository\org\openjfx\javafx-base\16\javafx-base-16-win.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-graphics\16\javafx-graphics-16-win.jar;C:\dev\fxdemo\target\classes;C:\Users\send2\.m2\repository\org\openjfx\javafx-controls\16\javafx-controls-16-win.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-fxml\16\javafx-fxml-16-win.jar -m org.jewelsea.fxdemo/org.jewelsea.fxdemo.TouchTest
java.version: 16.0.2
javafx.runtime.version: 16+8
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_PRESSED, consumed = false, touchCount = 1, eventSetId = 1, touchPoint = TouchPoint [state = PRESSED, id = 1, target = Pane@295c8184[styleClass=root], x = 394.5, y = 330.5, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.5, y = 330.5, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_MOVED, consumed = false, touchCount = 1, eventSetId = 2, touchPoint = TouchPoint [state = MOVED, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_STATIONARY, consumed = false, touchCount = 1, eventSetId = 3, touchPoint = TouchPoint [state = STATIONARY, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_STATIONARY, consumed = false, touchCount = 1, eventSetId = 4, touchPoint = TouchPoint [state = STATIONARY, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_RELEASED, consumed = false, touchCount = 1, eventSetId = 5, touchPoint = TouchPoint [state = RELEASED, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
执行行仅供参考,当我使用其内部运行函数启动应用程序时,它是由我的 IDE (Intellij Idea) 自动生成的。我确信它可以在 IDE 之外使用不同的执行命令正常工作,但使用相同的 JRE/JavaFX 版本。
示例适用于 JavaFX 16,不适用于 17.0.0.1
如果您使用当前版本的 JavaFX 17,则在我设置的运行 Windows 的 Surface Book 2 上,上述示例将不会接收触摸事件(它们映射到鼠标事件)。何塞对此问题的评论对此进行了解释:
JavaFX 16 发布后,此问题JDK-8249737 https://bugs.openjdk.java.net/browse/JDK-8249737已修复。它改变了 Windows 上处理触摸事件的方式:并非所有事件都是直接事件。在此修复之前,触摸事件会报告给场景,但现在间接事件会退出:link https://github.com/openjdk/jfx/blob/master/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java#L2799,并视为鼠标事件。
这也(大部分)适用于此处找到的旧 Oracle TouchEvent 教程示例代码:
- https://docs.oracle.com/javase/8/javafx/events-tutorial/touch_events.htm#CHDHBGJA https://docs.oracle.com/javase/8/javafx/events-tutorial/touch_events.htm#CHDHBGJA
该代码的多点触控文件夹拖动部分适用于我的 Java 16 设置。
该代码中将球拖到盒子部分对我来说在 Java 16 上不起作用。它似乎记录了初始触摸,但我无法计算出将球带到另一个盒子的触摸或触摸和拖动序列,因此它看起来已损坏。
对于 Java 17,触摸事件示例中没有任何内容响应触摸事件(或鼠标事件)。
FAQ
对于 MacOS,如果触控板事件也生成触摸事件就好了。
使用 Mac 触控板不会生成触摸事件(在 JavaFX 17 上测试)。与 Windows 触摸处理不同,我认为此 Mac 代码没有针对 JavaFX 17 进行更新,因此可能一直都是这样。我没有触摸屏来尝试。
对于 iOS 实现,通过检查代码可以看出,当您触摸 iOS 设备的屏幕时,它会生成触摸事件(但我还没有运行 JavaFX iOS 的设置来测试它)。
看来有多个问题。
是的我同意。
我还认为,有些问题是特定于平台和设备的,最终可能会有点微妙,而且并不完全简单。
我提供的信息几乎是我对这个主题的知识的限制,因此不幸的是,我无法提供更多帮助。
当我使用bell-sw或Azul Full-JDK 16测试它时,它不起作用
有点奇怪的是,它适用于 gluon JavaFX 16 发行版,但不适用于 azul 或 bell-sw 捆绑发行版,因为人们会认为它们具有相同的功能,但也只能说这么多了。
我想可以联系这些捆绑的 JDK/JavaFX 发行版的制造商,或者为此针对他们提交问题报告。但是,随着 Java 17 的功能发生变化,我不确定它会带来很大的变化,至少目前是这样。
当我使用 Oracle Java 17 并使用从 gluonhq.com/products/javafx 下载的 JavaFX 16 时,它确实有效!但 JavaFX 17 无论如何都不起作用。
是的,这与我使用来自 Maven 中心的模块化 JavaFX 版本得到的结果相同。
或者必须以不同的方式检索触摸事件?
我认为除了破解 JavaFX 核心之外,没有其他方法可以检索它们。该实现位于 JavaFX 库代码中,无法通过公共 API 进行配置。
对于某些平台(例如 iOS),触摸事件似乎是通过标准事件过滤器生成和路由的。
但对于其他平台,其中有特定的代码可以在某些情况下忽略 TouchEvents。至少对于 17.0.0.1 版本,在 JavaFX 框架中检测到 TouchEvent 时会被故意忽略。当您的手指触摸 Windows 操作系统设备上的触摸屏时,它们不会路由到用户 JavaFX 应用程序代码。请注意,在这种情况下,触摸将被视为 MouseEvents 并相应地执行操作 (AFAICT)。
因此,您需要自定义和更改核心 JavaFX 代码,以获取 Windows 操作系统平台上的触摸事件,方法是自行破解 JavaFX 库代码,或者将更改集成到未来 JavaFX 版本的库中。
关于 JavaFX TouchEvent 实现(及其更改)的思考
也许这个问题已经得到了彻底的考虑,并且 JavaFX 17.0.0.1 中的平台代码正在按设计运行。也许人们的想法是,当前的行为虽然不理想,但却是合理的妥协。也许结果可能是文档更新以更好地描述 TouchEvent 行为,而不是功能更新来更改它。
但在我看来,从目前的行为来看,当 JavaFX 在某些平台(例如 Windows 操作系统)上运行时,JavaFX 中的 TouchEvent 处理功能的设计和实现似乎存在问题。我不知道如何准确分类或解决这些问题。
如果您希望与 JavaFX 开发人员合作,我建议您加入openjfx-dev https://mail.openjdk.java.net/mailman/listinfo/openjfx-dev邮件列表并描述那里的问题(链接回这个问题)并开始讨论可以采取什么措施。