【问题标题】:Show some tabs ahead from selected tab in a JavaFx 8 TabPane header在 JavaFx 8 TabPane 标头中显示选定选项卡前面的一些选项卡
【发布时间】:2015-07-30 21:21:43
【问题描述】:

我正在尝试修改 JavaFx 8 中的 TabPage 控件,以使其向视口显示当前所选选项卡前面(右侧)的一些选项卡,或者如果所选选项卡位于标题的最左侧,它会在当前标签之前显示附近的标签。

现在怎么样了:

我如何让它表现得像:

当用户选择索引 X 的选项卡时,选项卡窗格标题会显示另外 2 或 3 个附近的选项卡。

这是我到目前为止尝试过的,但没有成功,显然下面的代码太快了,无法让界面线程按时同步选项卡选择(想法是提前选择一个选项卡,然后回退到由用户,使标题显示所选选项卡之后的选项卡):

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;

public class TabSelectionListener implements ChangeListener<Tab> {

    protected TabPane owner;
    protected boolean lock;
    protected int nextItems;

    TabSelectionListener(TabPane listenTo){
        owner = listenTo;
        lock = false;
        nextItems = 2;
    }

    TabSelectionListener(TabPane listenTo, int minimalInFront){
        owner = listenTo;
        lock = false;
        nextItems = minimalInFront;
    }

    @Override
    public void changed(ObservableValue<? extends Tab> list, Tab old, Tab newT) {
        int maxTab;
        int curTab;
        int i;

        // Locks this listener, because the selections owner.getSelectionModel().select(X)
        // will call this listener again, and we are calling those from here.
        if(!lock){
            lock = true;
            maxTab = owner.getTabs().size() - 1;
            curTab = owner.getSelectionModel().getSelectedIndex();

            for(i = 0; i < nextItems && curTab + i < maxTab; i++);
            owner.getSelectionModel().select(i); // int overload
            owner.getSelectionModel().select(newT);

            lock = false;
        }
    }
}

tabPane 为每个选项卡选择调用它:

tabPane.getSelectionModel().selectedItemProperty().addListener(new TabSelectionListener(tabPane,3));

一直在看这里的一些题目,感觉header其实是一个StackPane,可以通过执行获得:

StackPane region = (StackPane) tabPane.lookup(".headers-region");

它可以工作,但之后我不知道如何访问实现默认行为的属性。

有什么建议吗?

感谢阅读。

【问题讨论】:

    标签: java javafx javafx-8


    【解决方案1】:

    我终于做到了。

    发现我正在寻找的类是 com.sun.javafx.scene.control.skin.TabPaneSkin @ jfxrt.jar,它有一种方法可以使选定的选项卡可见,它每次在 TabPane 上的选定选项卡时运行不完全可见,我覆盖了它。

    TabPaneSkin 是 TabPane 的默认外观,它将一些行为应用于 TabPane 控件。

    /*
    * 版权所有 (c) 2011、2014,Oracle 和/或其附属公司。版权所有。
    * ORACLE 专有/机密。使用受许可条款的约束。
    *

    希望甲骨文不会介意...

    选择您的 TabPane,然后制作...

    tabPane.setSkin(new TabPaneNewSkin(tabPane));
    

    ...用我写的显示附近选项卡的这个覆盖 Oracle 的默认 TabPaneSkin。

    当一个选项卡被选中以使其可见时,用于重新定位选项卡的原始 Oracle 代码:

        private void ensureSelectedTabIsVisible() {
                // work out the visible width of the tab header
                double tabPaneWidth = snapSize(isHorizontal() ? getSkinnable().getWidth() : getSkinnable().getHeight());
                double controlTabWidth = snapSize(controlButtons.getWidth());
                double visibleWidth = tabPaneWidth - controlTabWidth - firstTabIndent() - SPACER;
    
                // and get where the selected tab is in the header area
                double offset = 0.0;
                double selectedTabOffset = 0.0;
                double selectedTabWidth = 0.0;
                for (Node node : headersRegion.getChildren()) {
                    TabHeaderSkin tabHeader = (TabHeaderSkin)node;
    
                    double tabHeaderPrefWidth = snapSize(tabHeader.prefWidth(-1));
    
                    if (selectedTab != null && selectedTab.equals(tabHeader.getTab())) {
                        selectedTabOffset = offset;
                        selectedTabWidth = tabHeaderPrefWidth;
                    }
                    offset += tabHeaderPrefWidth;
                }
    
                final double scrollOffset = getScrollOffset();
                final double selectedTabStartX = selectedTabOffset;
                final double selectedTabEndX = selectedTabOffset + selectedTabWidth;
    
                final double visibleAreaEndX = visibleWidth;
    
                if (selectedTabStartX < -scrollOffset) {
                    setScrollOffset(-selectedTabStartX);
                } else if (selectedTabEndX > (visibleAreaEndX - scrollOffset)) {
                    setScrollOffset(visibleAreaEndX - selectedTabEndX);
                }
            }
    

    我在自定义 TabPane 皮肤中编写的代码:

        // This function was overwritten
        private void ensureSelectedTabIsVisible() {
            // work out the visible width of the tab header
            double tabPaneWidth = snapSize(isHorizontal() ? getSkinnable().getWidth() : getSkinnable().getHeight());
            double controlTabWidth = snapSize(controlButtons.getWidth());
            double visibleWidth = tabPaneWidth - controlTabWidth - firstTabIndent() - SPACER;
    
    
            // and get where the selected tab is in the header area
            double offset = 0.0;
            double selectedTabOffset = 0.0;
            double selectedTabWidth = 0.0;
    
            // OVERWRITE
            // Makes the nearby 3 tabs for each side of the selected tab visible.
            ObservableList<Node> headersRegionChildren = headersRegion.getChildren();
            boolean nextTabs = false;
            int nextTabsCount = 0;
            int current = 0;
            int numOfTabsToShowNext = 3;
            int numOfTabsToShowBefore = 3;
            double tabHeaderPrefWidth;       
            TabHeaderSkin tabHeader;
    
            for (Node node : headersRegionChildren) {
                tabHeader = (TabHeaderSkin)node;
    
                tabHeaderPrefWidth = snapSize(tabHeader.prefWidth(-1));
    
               if (selectedTab != null && selectedTab.equals(tabHeader.getTab())) {
                        selectedTabWidth = tabHeaderPrefWidth;
    
                    // OVERWRITE: Finds the offset of the first tab in the limit numOfTabsToShowBefore before the selected one to be shown
                    for(int i = current - 1; i >= 0 && numOfTabsToShowBefore > 1; i--, numOfTabsToShowBefore--){
                        tabHeader = (TabHeaderSkin)headersRegionChildren.get(i);
                        tabHeaderPrefWidth = snapSize(tabHeader.prefWidth(-1));
                        offset -= tabHeaderPrefWidth;
                        selectedTabWidth += tabHeaderPrefWidth;
                    }
    
                    selectedTabOffset = offset;
                    // OVERWRITE: Sets the flag to start counting in the next 3 nearby tabs.  
                    nextTabs = true;
                }
                // OVERWRITE: Sums the width of the next nearby tabs with the
                // width of the selected tab, so it will scroll enough to show
                // them too.
                if(nextTabs && nextTabsCount < numOfTabsToShowNext){
                    selectedTabWidth += tabHeaderPrefWidth;
                    nextTabsCount++;
                }else if(nextTabsCount == numOfTabsToShowNext){
                    break;
                }
    
                offset += tabHeaderPrefWidth;
                current++;
            }
            // END OVERWRITE
    
            final double scrollOffset = getScrollOffset();
            final double selectedTabStartX = selectedTabOffset;
            final double selectedTabEndX = selectedTabOffset + selectedTabWidth;
    
            final double visibleAreaEndX = visibleWidth;
    
            if (selectedTabStartX < -scrollOffset) {
                setScrollOffset(-selectedTabStartX);
            } else if (selectedTabEndX > (visibleAreaEndX - scrollOffset)) {
                setScrollOffset(visibleAreaEndX - selectedTabEndX);
            }
        }
    

    对于每个选项卡选择,上面的代码都会在所选选项卡的每一侧显示最近的 3 个选项卡(如果其中一个不在屏幕上并且存在)。

    原来如此。 com.sun.javafx.scene.control.skin.TabPaneSkin 不应该扩展,几乎每个方法都是私有的,所以我复制了它,只更改了上面提到的函数,并将其重命名为 TabPaneNewSkin,它是在我的包裹里。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-17
      • 1970-01-01
      • 2017-01-28
      • 2013-01-02
      • 1970-01-01
      • 2016-09-14
      • 2014-07-16
      • 1970-01-01
      相关资源
      最近更新 更多