How to detect when JavaFx mouse event occurs in the "label" are of a TitledPane?

1.6k views Asked by At

I have an Accordian with multiple TitledPanes. When a TitledPane is expanded, there are "dead areas" on the pane that do not have sub-components (e.g., buttons, text, etc.).

Right now, when I check MouseEvent.getSource(), it returns an instance of TitledPane for all areas. Is there a way to specifically constrain/check for a mouse-click on the "title" section of the TitledPane?

2

There are 2 answers

3
Omid On BEST ANSWER

I don't think there is a public API to detect mouse click on title region, however it is possible to do that this way:

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

But this method is highly discouraged as it relies on some internal implementation detail that may be subject to change.

May be it's better to think more about what you actually need. Maybe your actual requirement can be fulfilled by uisng TitledPane's public API methods and properties.

For insatnce expandedProperty()'s value gets changed every time mouse click occurs on title region (if isCollapsible() is set to 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);
    }
});
1
fabian On

In the css reference you can find out that there is a child of the TitledPane that has the style class title. It isn't hard to guess that this part is the title. You can go from the pick result up through the scene graph until you either find a node with the style class title or until you reach the Accordion.

The following code colors the rect below the Accordion green, iff the mouse is on a title and red otherwise:

@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();
}

Note that with an event filter for MouseEvent.MOUSE_CLICKED you could simply consume the event, if the pick result is not in a title...