0

So I have worked with java Swing for a long time for programming GUI and recently am trying to move to JavaFX. Thus, the question:

I am currently creating a search bar that opens when the user clicks the search button, and then closes when the user clicks off the search bar. In order to detect the click off, I added an EventFilter to the main scene in order to listen for global clicks. I then check the target of the click to see if the click was on components (sorry for the swing terminology) of the search bar, or not. If the click is not in the search bar, close the bar.

primaryStage.getScene().addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent mouseEvent) {
            System.out.println(mouseEvent.getTarget());
            if(!(mouseEvent.getTarget().equals(searchBarFill) || mouseEvent.getTarget().equals(searchBackground) || mouseEvent.getTarget().equals(searchBarField))){
                if(searchBarOpen){
                    searchBarFill.radiusProperty().unbind();
                    searchBackground.setDisable(false);
                    searchBarOpen = false;
                    Timeline shrink = new Timeline();
                    Timeline fadeIn = new Timeline();
                    shrink.setAutoReverse(true);
                    KeyValue kv = new KeyValue(searchBarFill.radiusProperty(), 0, Interpolator.EASE_BOTH);
                    KeyFrame kf = new KeyFrame(Duration.millis(250), kv);
                    KeyValue kv2 = new KeyValue(searchBackground.opacityProperty(), 1.0, Interpolator.EASE_BOTH);
                    KeyFrame kf2 = new KeyFrame(Duration.millis(100), kv2);
                    shrink.getKeyFrames().add(kf);
                    fadeIn.getKeyFrames().add(kf2);
                    SequentialTransition timeline = new SequentialTransition(shrink, fadeIn);
                    timeline.play();

                }
            }
        }
    });

//This pane holds all search bar Nodes (components)
        Pane searchBarPane = new Pane();
        searchBarPane.setMaxHeight(50);
        headerSearchContainer.getChildren().add(searchBarPane);

If there is a clearly better way of doing this, I would love to know. In programming in swing, I would solve this by checking the target of the mouse press against SwingUtilities.isDescendingFrom(the parent holding on search bar components, the click target). This would let me know whether or not the click was on any of the search bar components.

I have tried to explicitly list out all components in the search bar, but the search bar contains a TextField that registers press targets on the field, the text itself, a random Pane object, and much more nested Nodes i guess?

Is there a similar command in JavaFX, or even a better way of going about this in JavaFX? Thanks

  • I don't understand why you need an `EventFilter`. If you have a `Button` (ToggleButton is probably better in this situation), you just do the logic the `Button`'s `onAction` event handler. https://code.makery.ch/blog/javafx-8-event-handling-examples/ – SedJ601 Jan 06 '19 at 03:26
  • I reread your question. You need to set the `Focus` to the Search Bar once the button is pressed. You then need to listen to see when the Search Bar looses `Focus`. https://stackoverflow.com/questions/16549296/how-perform-task-on-javafx-textfield-at-onfocus-and-outfocus. – SedJ601 Jan 06 '19 at 03:33
  • You can register a listener for each `Node` in your search bar. No need to be checking for global mouse events and then trying to retrieve the target with coordinates. – Zephyr Jan 06 '19 at 04:09
  • @Sedrick So I would just set the focus on the Pane that holds all my search bar Nodes, and then listen for when it loses focus? There are many different nodes (components) that make up the search bar, such as open and close buttons, textfield, tooltip buttons, etc. And each of these additional components in the search bar have mouse listeners and such on them as well. Will that still work for using lost focus as a method? – Brandon Beiler Jan 06 '19 at 22:48
  • @Zephyr My issue is that I want to check when the user clicks away from the search bar. So I need to somehow register when a user clicks on anything but the search bar – Brandon Beiler Jan 06 '19 at 22:50

1 Answers1

0

I ended up going the route of doing an extensive search to check if the target component of the click was a descendant of my top level node. code and explanation in this answer

    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;
}

Then, when a click comes in, if the target is not a descendant of the top level node of the search bar, the bar is closed.