JavaFX 从 TabContent(Node) 访问 Tab 或 TabPane

JavaFX get access to a Tab or TabPane from a TabContent(Node)

如果您仅引用 Tab 中的 Node 例如

TabPane tabPane = new TabPane();
Tab tab = new Tab();
tab.setText("new tab");
Rectangle drect = new Rectangle(200,200, Color.LIGHTSTEELBLUE);
tab.setContent(drect);
tabPane.getTabs().addAll(tab,new Tab("tab 2"));

假设我只参考了 drect 我怎样才能得到 tab。 我对 Node.setUserData()drect.getParent().getClass().getName() return 不感兴趣 TabPaneSkin anon inner class TabContentRegion: 两个陌生人。

我想说的是 Node.getParent() 应该 return parent Node , 一般 uni-knowledge ( 节点在场景图中的表示可以使用 getParent() ) 进行跟踪,但是,当涉及到 Tab 时,它的都错了,所以我的问题

编辑

为什么我需要这个,假设你有 TabPane 由很多 Tab 组成,在一个特定的 Tab 中你有一个 TreeView 作为它的 Node-Content,它是根据某些条件选择的,对于那个特定的 TreeView,你有不同的自定义 Cell,因为它的 TreeItem 在 UI 和功能上有所不同,比如改变 styles 绑定 Fonts& 其他可绑定对象和动画 TabTabPane 中隐藏其他 Tab,关闭其他 Tabs

在这种情况下,遵循这种方法对我来说似乎是合法的,因为您不会做不必要的事情,例如将 children 暴露在恶劣天气下。 :-)

谢谢先生 James_D

Tab 本身不是Node,因此您无法通过以任何方式遍历场景图来获取选项卡。如果您在层次结构中走得足够远,您可以到达 TabPane。例如:

private TabPane findTabPaneForNode(Node node) {
    TabPane tabPane = null ;

    for (Node n = node.getParent(); n != null && tabPane == null; n = n.getParent()) {
        if (n instanceof TabPane) {
            tabPane = (TabPane) n;
        }
    }

    return tabPane ;
}

将 return 最近的 TabPane 包含传入的节点,或者 null 如果节点不在选项卡窗格中。

但是,需要这个就好像你的设计是错误的。如果您将一个节点放在选项卡窗格中,则在某个时候您会创建一个选项卡,因此您应该只组织您的代码,以便您可以引用该选项卡。

我知道这是一个有点老的问题,但我会 post 为仍在为这个问题苦苦挣扎的人提供解决方案。

下面是TabPane.

的FXML结构示例
<!-- (1) -->
<TabPane>
  <tabs>
    <!-- (2) -->
    <Tab>
      <!-- (3) -->
      <content>
        <!-- (4) -->
        <Pane>
          <!-- (5) -->
          <Node />
        </Pane>
      </content>
    </Tab>
  </tabs>
</TabPane>

以下方法 returns Tab 对象,其中包含指定为参数的 Node

public static Tab getParentTab1(Node node) {
    // <TabPane> object (described as (1) in the FXML example)
    TabPane tabPane = null;

    // <Tab> object (described as (2))
    Tab tab = null;

    // The object of the tab content area
    Node tabContentRegion = null;

    ClassLoader loader = ClassLoader.getSystemClassLoader();
    Class<?> innerClass = null;

    try {
        innerClass = loader.loadClass("com.sun.javafx.scene.control.skin.TabPaneSkin$TabContentRegion");
    } catch (ClassNotFoundException ex) {
        ex.printStackTrace();
    }

    for (Node n = node.getParent(); n != null && tabPane == null; n = n.getParent()) {
        // If the node is an instance of the inner class of TabPaneSkin
        if (n.getClass().isAssignableFrom(innerClass)) {
            tabContentRegion = n;
        }

        if (n instanceof TabPane) {
            tabPane = (TabPane) n;
        }
    }

    if (tabPane != null && tabContentRegion != null) {
        // The list of the <Tab> objects
        ObservableList<Tab> tabList = tabPane.getTabs();

        for (Tab t : tabList) {
            // t.getContent() returns the first <Node> object on the <Tab> (most likely it's a <Pane> described as (4))
            // t.getContent().getParent() returns the TabPaneSkin$TabContentRegion object
            System.out.println("content: " + t.getContent());
            System.out.println("parent: " + t.getContent().getParent());

            if (t.getContent().getParent().equals(tabContentRegion)) {
                tab = t;
                break;
            }
        }
    }

    return tab;
}
  1. 获取TabPane对象和Tabtab内容区域 来自 Node 个对象的对象。

  2. 扫描 TabPane 中包含的所有 Tab 个对象(在阶段 #1 中检索)。

  3. 获取 Tab 对象,其内容区域等于 选项卡内容区域(在阶段 #1 中检索到)。

更简单的方法如下所示。

public Tab getParentTab2(Node node) {
    TabPane tabPane = null;
    Tab tab = null;
    Node tabContentRegion = null;

    for (Node n = node.getParent(); n != null && tabPane == null; n = n.getParent()) {
        if (n.getStyleClass().contains("tab-content-area")) {
            tabContentRegion = n;
        }

        if (n instanceof TabPane) {
            tabPane = (TabPane) n;
        }
    }

    if (tabPane != null && tabContentRegion != null) {
        // The list of the <Tab> objects
        ObservableList<Tab> tabList = tabPane.getTabs();

        for (Tab t : tabList) {
            if (t.getContent().getParent().equals(tabContentRegion)) {
                tab = t;
                break;
            }
        }
    }

    return tab;
}

这是我的解决方案

获取 TabPane:

private TabPane getParentTabPane(Node node) {

    if(node==null)
        return null;

    final Parent parent = node.getParent();
    return Optional.of(parent).filter(TabPane.class::isInstance).map(TabPane.class::cast).orElseGet(()->getParentTabPane(parent));
}

获取标签:

private Tab getParentTab(Node node) {

    Tab tab = null;
    while(node!=null) {

        final Parent stackPane = node.getParent();
        if(!(stackPane instanceof StackPane)) {
            node = stackPane;
            continue;
        }

        final Parent tabPane = stackPane.getParent();
        if(!(tabPane instanceof TabPane)) {
            node = tabPane;
            continue;
        }

        final Node n = node;
        tab = Optional.ofNullable((TabPane)tabPane).map(TabPane::getTabs).map(List::parallelStream).orElseGet(()->Stream.empty()).filter(t->t.getContent()==n).findAny().orElse(null);
        break;
    }

     return tab;
}