[英]Show some tabs ahead from selected tab in a JavaFx 8 TabPane header
我正在嘗試修改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));
我一直在閱讀這里的一些主題,在我看來,標題實際上是一個StackPane,可以通過執行:
StackPane region = (StackPane) tabPane.lookup(".headers-region");
它可以工作,但之后我不知道如何訪問實現默認行為的屬性。
有什么建議?
謝謝閱讀。
我終於做到了。
發現我正在尋找的類是com.sun.javafx.scene.control.skin.TabPaneSkin @jfxrt.jar,它有一個方法可以使選定的選項卡可見,它每次TabPane上的選定選項卡都不完整時運行可見,我覆蓋了它。
TabPaneSkin是TabPane的默認外觀,它將一些行為應用於TabPane控件。
/ *
*版權所有(c)2011,2014,Oracle和/或其附屬公司。 版權所有。
* 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,它是在我的包裹。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.