JavaFX:如何在单击TabPane标题时设置监听器

huangapple go评论87阅读模式
英文:

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

问题

这是一个奇怪的问题,所以我会尽力清楚地解释自己。

我想要的是在单击TabPane中的选项卡时触发一个事件,而我所说的"单击"仅指单击,不一定是选中。

我已经尝试使用Tab的selectedProperty,但只有在选项卡未选中时,才会调用事件,即使选项卡已经选中,也不会触发。

我这样做的原因是,我正在尝试制作一个可折叠的选项卡窗格,如果再次单击已打开的选项卡,它会隐藏TabPane的内容,我已经编写了折叠TabPane的代码,但是...我不知道如何从选项卡标题获取单击事件。

我甚至查看了TabPane的源代码,希望能找到选项卡标题容器,但我在那里没有找到它。

英文:

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.

答案1

得分: 4

不需要完全新的皮肤 - 我们可以通过查找来访问标题节点。请注意:这意味着依赖于实现细节,这些细节可能在不同版本之间发生变化。

要查找的(未记录的!)样式 ID 是“.tab-container” - 这是 TabHeaderSkin 的唯一子节点(单个标签标题的区域)。它包含标签、关闭按钮(如果有的话)和焦点标记。这个“皮肤”在其属性中保存对其标签的引用(当然是未记录的 ;))。

所以基本的方法是:

  • 在安装皮肤后查找所有标签容器
  • 对于每个容器,在其父节点上注册适当的鼠标处理程序
  • 在相应的鼠标事件上执行所需操作

请注意,必须在修改标签列表时添加/移除监听器(在下面的片段中未包含)。

在示例代码中:

/**
 * 查找标签标题的样式部分并安装一个鼠标处理程序,该处理程序调用工作负载方法。
 * 
 * @param tabPane
 */
private void installTabHandlers(TabPane tabPane) {
    Set<Node> headers = tabPane.lookupAll(".tab-container");
    headers.forEach(node -> {
        // 实现细节:tabContainer的标题是TabHeaderSkin
        Parent parent = node.getParent();
        parent.setOnMouseClicked(ev -> handleHeader(parent));
    });
}

/**
 * 标签的工作负载。
 * @param tabHeaderSkin
 */
private void handleHeader(Node tabHeaderSkin) {
    // 实现细节:皮肤保留对关联标签的引用
    Tab tab = (Tab) tabHeaderSkin.getProperties().get(Tab.class);
    System.out.println("为标签执行操作:" + tab.getText());
}
英文:

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 JavaFX:如何在单击TabPane标题时设置监听器

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&lt;Node&gt; headers = tabPane.lookupAll(&quot;.tab-container&quot;);
    headers.forEach(node -&gt; {
        // implementation detail: header of tabContainer is the TabHeaderSkin
        Parent parent = node.getParent();
        parent.setOnMouseClicked(ev -&gt; 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(&quot;do stuff for tab: &quot; + tab.getText());
}

huangapple
  • 本文由 发表于 2020年7月28日 19:21:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/63132948.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定