javafx - 如何将键事件分派到鼠标下方的正确 JavaFX 形状?
问题描述
我有一个Scene
带有几个不同Group
s 的 JavaFX。每组有几个填充PolyLine
的 s。
n当用户在填充PolyLine
的 s之一内按下键时,我想触发一些计算。
我曾经scene.setOnKeyPressed
安装一个KeyEvent
处理程序并将其打印出来。我不确定如何确定PolyLine
事件发生在哪个时间点。该target
事件恰好是Button
我关注的早期教程的遗留问题。事件打印输出不显示任何坐标,即使有一些坐标,我也不确定如何最好地遍历Node
树来寻找PolyLine
感兴趣的坐标。
响应鼠标悬停在 JavaFX 上时发生的关键事件的正确习惯用法是Shape
什么?
解决方案
关键事件仅传递给Node
具有焦点的那个。Node
您可以通过调用来请求获得焦点Node#requestFocus()
。使用它,一种解决方案是您可以将鼠标事件处理程序添加到每个Shape
在鼠标进入该区域时请求焦点的事件处理程序。然后将关键事件处理程序添加到每个Shape
而不是Scene
. 键事件将被传递给Node
具有焦点的 并由其处理,焦点将是Shape
鼠标悬停在其上的 。一旦鼠标离开该区域,要停止将关键事件传递到Shape
该区域,您可以添加一个请求焦点的处理程序(例如,公共父级或场景的根)。
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
public final class App extends Application {
@Override
public void start(Stage primaryStage) {
var root = new HBox(15, createCircle(), createTriangle(), createSquare());
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(30));
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Shapes");
primaryStage.show();
}
private Shape createCircle() {
var circle = new Circle(100);
addHandlers(circle, "Circle");
return circle;
}
private Shape createTriangle() {
var polygon = new Polygon(100, 0, 200, 200, 0, 200, 100, 0);
addHandlers(polygon, "Triangle");
return polygon;
}
private Shape createSquare() {
var rectangle = new Rectangle(200, 200);
addHandlers(rectangle, "Square");
return rectangle;
}
private void addHandlers(Shape shape, String name) {
// Notice you have access to the specific shape in the
// event handlers. The source of the event will also
// be the shape.
shape.setOnMouseEntered(event -> {
if (!shape.isFocused()) {
event.consume();
shape.requestFocus();
}
});
shape.setOnMouseExited(event -> {
if (shape.isFocused()) {
event.consume();
shape.getScene().getRoot().requestFocus();
}
});
shape.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.N) {
event.consume();
System.out.println("KEY_PRESSED['N']: " + name);
}
});
}
}
添加事件处理程序的另一个MOUSE_ENTERED
选择是监听. 当它变为 时,请求焦点;当它变为 时,移除焦点。MOUSE_EXITED
Node#hover
Shape
true
false
请求拥有焦点会将焦点从当前拥有焦点Shape
的焦点上拉开。Node
例如,如果您有TextField
焦点,那么只要鼠标悬停在其中一个Shape
s 上,它就会失去焦点。这将阻止用户输入TextField
(直到他们去点击它)。
如果这种行为是不可取的,那么您可以维护一些字段/属性/模型来告诉您Shape
当前悬停在哪个字段/属性/模型上,而不是请求焦点。然后,您将事件过滤器TextField
添加到and的共同父级Shape
。如果 aShape
将鼠标悬停在它上面,则执行必要的操作,然后使用该事件(这将阻止它到达任何Node
具有焦点的事件)。
推荐阅读
- python - Python 3:从 tar.gz 存档中提取文件
- jetty - Apache Karaf 中无法安装 Keycloak 码头适配器
- html - 在运行动画时如何定位 HTML 元素
- wpf - 选择 tabitem 时从 TabItem 标题中删除下划线
- clickhouse - 如何有效监控 Clickhouse 实例(GCP)
- r - 根据 r 中的多个标准在数据框中创建一个新变量
- node.js - jest + mongoose 给出带有数组数组的错误模式
- apache-flink - 在 flink 中的链式运算符中分配负载
- spring - 测试时如何以不同方式配置 Spring @Component
- django - 带有动态 app_label 的 django url 标签