如何确定用户是否在特定JavaFX节点外单击?

时间:2016-07-01 03:07:49

标签: java javafx

我有一个TextField,如果用户点击任何而不是TextField本身,我想做点什么。

  • 显然,如果您不单击节点本身,onMouseClicked事件将不会触发,因此无效。
  • focusedProperty可能是一个好主意,但问题是几乎我的整个应用程序都不能通过焦点,因此在很多情况下,在文本区外点击不会使它失焦,所以听众将不会收到通知。

我唯一想到的就是在场景上放置一个事件过滤器,拦截鼠标点击,获取点击坐标并确定它们是否属于文本域的范围。我发现这有点矫枉过正,我可能会遗漏一些更明显的东西。

是否有另一种方法可以确定用户是否点击了TextField节点之外的任何位置?

2 个答案:

答案 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中有任何其他控件。鼠标单击不会干扰它们,只有在您直接单击窗格时才会调用它。