我有一个TextField
,如果用户点击任何而不是TextField
本身,我想做点什么。
onMouseClicked
事件将不会触发,因此无效。focusedProperty
可能是一个好主意,但问题是几乎我的整个应用程序都不能通过焦点,因此在很多情况下,在文本区外点击不会使它失焦,所以听众将不会收到通知。我唯一想到的就是在场景上放置一个事件过滤器,拦截鼠标点击,获取点击坐标并确定它们是否属于文本域的范围。我发现这有点矫枉过正,我可能会遗漏一些更明显的东西。
是否有另一种方法可以确定用户是否点击了TextField
节点之外的任何位置?
答案 0 :(得分:4)
我唯一想到的就是在场景上放置一个事件过滤器,拦截鼠标点击,获取点击坐标并确定它们是否属于文本域的范围。我发现这有点矫枉过正,我可能会遗漏一些更明显的东西。
事实上,我认为这是你最好的选择,但有一个变化:
使用the PickResult
provided by the MouseEvent
获取目标Node
并检查其是否在Node
的层次结构中。
(如果Node
有孩子,这可能是必要的;例如TextField
也包含Text
元素。)
事实上,这似乎是唯一不能通过在场景图中的某个地方使用事件来打破它。
如果用户点击TextField
以外的某处,则会将焦点移至根窗格。
public static boolean inHierarchy(Node node, Node potentialHierarchyElement) {
if (potentialHierarchyElement == null) {
return true;
}
while (node != null) {
if (node == potentialHierarchyElement) {
return true;
}
node = node.getParent();
}
return false;
}
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
textField.setMinSize(400, Region.USE_PREF_SIZE);
textField.setMaxWidth(400);
textField.setEditable(false);
textField.textProperty().bind(Bindings.when(textField.focusedProperty()).then("Got the Focus!").otherwise("Please give me the focus!"));
StackPane root = new StackPane();
root.getChildren().add(textField);
Scene scene = new Scene(root, 500, 200);
scene.addEventFilter(MouseEvent.MOUSE_CLICKED, evt -> {
if (!inHierarchy(evt.getPickResult().getIntersectedNode(), textField)) {
root.requestFocus();
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
答案 1 :(得分:0)
假设您应用的顶级容器为Pane
。您可以将鼠标单击事件应用于该窗格,并在其内部处理文本字段的鼠标单击事件。这样,如果用户点击textfield
或点击其他地方,则会通知这两个事件。这是示例代码。
Pane.setOnMouseClicked((MouseEvent evt) -> {
System.out.println("Click outside textfield");
textField.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
System.out.println("textfield clicked");
}
});
});
如果您在Pane
中有任何其他控件。鼠标单击不会干扰它们,只有在您直接单击窗格时才会调用它。