如何检测 TitledPane 的 "label" 中何时发生 JavaFx 鼠标事件?
How to detect when JavaFx mouse event occurs in the "label" are of a TitledPane?
我有一个带有多个 TitledPanes 的 Accordian。展开 TitledPane 时,窗格上有 "dead areas" 个没有子组件(例如,按钮、文本等)。
现在,当我检查 MouseEvent.getSource() 时,它 returns 是所有区域的 TitledPane 实例。有没有办法专门 constrain/check 鼠标单击 TitledPane 的 "title" 部分?
我不认为有 public API 可以检测鼠标点击标题区域,但是可以这样做:
titledPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
EventTarget target = event.getTarget();
String clazz = "class com.sun.javafx.scene.control.skin.TitledPaneSkin$TitleRegion";
if(target.getClass().toString().equals(clazz) || // anywhere on title region except title Text
(target instanceof Node && ((Node) target).getParent().getClass().toString().equals(clazz))) // title Text
System.out.println("title was clicked");
}
});
但是这种方法非常不鼓励,因为它依赖于一些可能会发生变化的内部实现细节。
可能最好多想想自己真正需要什么。也许您的实际需求可以通过 uisng TitledPane
的 public API 方法和属性来满足。
例如,每次鼠标点击标题区域时 expandedProperty()
的值都会改变(如果 isCollapsible()
设置为 true
)。
titledPane.expandedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println("mouse click changed expanded from " + oldValue + " to " + newValue);
}
});
In the css reference 你可以发现 TitledPane
中有一个 child 的样式是 class title
。不难猜到这部分就是标题。您可以从拾取结果向上遍历场景图,直到找到样式为 class title
的节点或到达 Accordion
.
以下代码将 Accordion
下方的矩形着色为绿色,前提是鼠标位于标题上,否则为红色:
@Override
public void start(Stage primaryStage) {
TitledPane tp1 = new TitledPane("foo", new Rectangle(100, 100));
TitledPane tp2 = new TitledPane("bar", new Circle(100));
Accordion accordion = new Accordion(tp1, tp2);
Rectangle rect = new Rectangle(100, 20, Color.RED);
accordion.addEventFilter(MouseEvent.MOUSE_MOVED, evt -> {
Node n = evt.getPickResult().getIntersectedNode();
boolean title = false;
while (n != accordion) {
if (n.getStyleClass().contains("title")) {
// we're in the title
title = true;
break;
}
n = n.getParent();
}
rect.setFill(title ? Color.LIME : Color.RED);
});
Scene scene = new Scene(new VBox(accordion, rect), 100, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,使用 MouseEvent.MOUSE_CLICKED
的事件过滤器,如果选择结果不在标题中,您可以简单地使用事件...
我有一个带有多个 TitledPanes 的 Accordian。展开 TitledPane 时,窗格上有 "dead areas" 个没有子组件(例如,按钮、文本等)。
现在,当我检查 MouseEvent.getSource() 时,它 returns 是所有区域的 TitledPane 实例。有没有办法专门 constrain/check 鼠标单击 TitledPane 的 "title" 部分?
我不认为有 public API 可以检测鼠标点击标题区域,但是可以这样做:
titledPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
EventTarget target = event.getTarget();
String clazz = "class com.sun.javafx.scene.control.skin.TitledPaneSkin$TitleRegion";
if(target.getClass().toString().equals(clazz) || // anywhere on title region except title Text
(target instanceof Node && ((Node) target).getParent().getClass().toString().equals(clazz))) // title Text
System.out.println("title was clicked");
}
});
但是这种方法非常不鼓励,因为它依赖于一些可能会发生变化的内部实现细节。
可能最好多想想自己真正需要什么。也许您的实际需求可以通过 uisng TitledPane
的 public API 方法和属性来满足。
例如,每次鼠标点击标题区域时 expandedProperty()
的值都会改变(如果 isCollapsible()
设置为 true
)。
titledPane.expandedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println("mouse click changed expanded from " + oldValue + " to " + newValue);
}
});
In the css reference 你可以发现 TitledPane
中有一个 child 的样式是 class title
。不难猜到这部分就是标题。您可以从拾取结果向上遍历场景图,直到找到样式为 class title
的节点或到达 Accordion
.
以下代码将 Accordion
下方的矩形着色为绿色,前提是鼠标位于标题上,否则为红色:
@Override
public void start(Stage primaryStage) {
TitledPane tp1 = new TitledPane("foo", new Rectangle(100, 100));
TitledPane tp2 = new TitledPane("bar", new Circle(100));
Accordion accordion = new Accordion(tp1, tp2);
Rectangle rect = new Rectangle(100, 20, Color.RED);
accordion.addEventFilter(MouseEvent.MOUSE_MOVED, evt -> {
Node n = evt.getPickResult().getIntersectedNode();
boolean title = false;
while (n != accordion) {
if (n.getStyleClass().contains("title")) {
// we're in the title
title = true;
break;
}
n = n.getParent();
}
rect.setFill(title ? Color.LIME : Color.RED);
});
Scene scene = new Scene(new VBox(accordion, rect), 100, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,使用 MouseEvent.MOUSE_CLICKED
的事件过滤器,如果选择结果不在标题中,您可以简单地使用事件...