简体   繁体   中英

JavaFX: How to set a listener to the TabPane header onClick event

This is a weird question so I'll make my best to explain myself properly.

What I'd like is to trigger an event when a Tab in a TabPane get clicked, and by "clicked" I mean just clicked, not necessarily selected.

I already tried using the selectedProperty of the Tab , but that does call the event only if the Tab is clicked when it's not selected, not even if it's clicked when it's already selected.

The reason why I'm doing this is that I'm trying to make a collapsible tab pane that hides the content of the TabPane if you click again on the opened tab, I've already wrote the code for collapsing the TabPane and that works but... I have no idea on how to get a click event from the tab header.

I've even looked into TabPane source code too hoping that I could find the tab header container but I didn't find it there.

No need for a completely new skin - we can access the header nodes by lookup. Beware: implies relying on implementation details, which might change across versions.

The (undocumented.) style id to look for is ".tab-container" - that's the only child of the TabHeaderSkin (== region for a single tab header), It contains the label. the close button (if any) and the focus marker, This "skin" keeps a reference to its tab in its properties (undocumented; of course ;)

So the basic approach is to

  • lookup all tab-containers after the skin is installed
  • for each, register an appropriate mouse handler on its parent
  • on the respective mouseEvent, do whatever is needed

Note that the listeners have to be removed/added when the list of tabs is modified (not included in the snippet below).

In example code:

/** 
 * looks up the styled part of tab header and installs a mouseHandler
 * which calls the work load method.
 * 
 * @param tabPane
 */
private void installTabHandlers(TabPane tabPane) {
    Set<Node> headers = tabPane.lookupAll(".tab-container");
    headers.forEach(node -> {
        // implementation detail: header of tabContainer is the TabHeaderSkin
        Parent parent = node.getParent();
        parent.setOnMouseClicked(ev -> handleHeader(parent));
    });
}

/**
 * Workload for tab.
 * @param tabHeaderSkin
 */
private void handleHeader(Node tabHeaderSkin) {
    // implementation detail: skin keeps reference to associated Tab
    Tab tab = (Tab) tabHeaderSkin.getProperties().get(Tab.class);
    System.out.println("do stuff for tab: " + tab.getText());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM