0

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?

SoCal
  • 801
  • 1
  • 10
  • 23

2 Answers2

0

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);
    }
});
Omid
  • 5,823
  • 4
  • 41
  • 50
  • Thanks @Omid! I ended up building on your second suggestion, looking at the "expanded" property (via _italic_isExpanded()_italic_), as there are other factors I needed to include. But, being able to identify the event's source and the expanded state of the source TitledPane allows me to reliably control the behavior. – SoCal Dec 21 '16 at 17:06
  • 1
    For additional clarity, what I really needed to know was "is the TitledPane being closed?" TitledPane.isExpanded() only returns false when the TitledPane is being closed, which only occurs if the mouse-click is on the TitledPane's title Label. Again, thanks for helping me to better focus on what I really needed to be checking. – SoCal Dec 21 '16 at 18:01
  • You're welcome. Most of the times if we are trying to use a non-public API in a non-standard way, then something is wrong. – Omid Dec 22 '16 at 06:36
0

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...

fabian
  • 80,457
  • 12
  • 86
  • 114
  • Thanks @fabian. This works, but I went with the suggested approach below. Mostly because I felt better about basing my implementation on the state of the TitledPane that is the source of the MouseEvent, vice on the presence of a text value in a property. But, again, thanks for the suggestion, and it does, indeed, work. – SoCal Dec 21 '16 at 17:11