@@ -152,7 +152,6 @@ private enum TabAnimationState {
152152 private Rectangle clipRect ;
153153 private Rectangle tabHeaderAreaClipRect ;
154154 private Tab selectedTab ;
155- private boolean isSelectingTab ;
156155
157156 private final TabPaneBehavior behavior ;
158157
@@ -200,8 +199,14 @@ public TabPaneSkin(TabPane control) {
200199
201200 registerChangeListener (control .selectionModelProperty (), e -> updateSelectionModel ());
202201 registerChangeListener (control .sideProperty (), e -> updateTabPosition ());
203- registerChangeListener (control .widthProperty (), e -> clipRect .setWidth (getSkinnable ().getWidth ()));
204- registerChangeListener (control .heightProperty (), e -> clipRect .setHeight (getSkinnable ().getHeight ()));
202+ registerChangeListener (control .widthProperty (), e -> {
203+ tabHeaderArea .invalidateScrollOffset ();
204+ clipRect .setWidth (getSkinnable ().getWidth ());
205+ });
206+ registerChangeListener (control .heightProperty (), e -> {
207+ tabHeaderArea .invalidateScrollOffset ();
208+ clipRect .setHeight (getSkinnable ().getHeight ());
209+ });
205210
206211 selectedTab = getSkinnable ().getSelectionModel ().getSelectedItem ();
207212 // Could not find the selected tab try and get the selected tab using the selected index
@@ -214,7 +219,6 @@ public TabPaneSkin(TabPane control) {
214219 getSkinnable ().getSelectionModel ().selectFirst ();
215220 }
216221 selectedTab = getSkinnable ().getSelectionModel ().getSelectedItem ();
217- isSelectingTab = false ;
218222
219223 initializeSwipeHandlers ();
220224 }
@@ -432,7 +436,7 @@ public TabPaneSkin(TabPane control) {
432436
433437 private SelectionModel <Tab > selectionModel ;
434438 private InvalidationListener selectionChangeListener = observable -> {
435- isSelectingTab = true ;
439+ tabHeaderArea . invalidateScrollOffset () ;
436440 selectedTab = getSkinnable ().getSelectionModel ().getSelectedItem ();
437441 getSkinnable ().requestLayout ();
438442 };
@@ -678,7 +682,7 @@ private void removeTabContent(Tab tab) {
678682 }
679683
680684 private void updateTabPosition () {
681- tabHeaderArea .setScrollOffset ( 0.0F );
685+ tabHeaderArea .invalidateScrollOffset ( );
682686 getSkinnable ().applyCss ();
683687 getSkinnable ().requestLayout ();
684688 }
@@ -809,6 +813,7 @@ class TabHeaderArea extends StackPane {
809813 private boolean measureClosingTabs = false ;
810814
811815 private double scrollOffset ;
816+ private boolean scrollOffsetDirty = true ;
812817
813818 public TabHeaderArea () {
814819 getStyleClass ().setAll ("tab-header-area" );
@@ -842,13 +847,13 @@ public TabHeaderArea() {
842847 if (tabsFit ()) {
843848 setScrollOffset (0.0 );
844849 } else {
845- if (isSelectingTab ) {
850+ if (scrollOffsetDirty ) {
846851 ensureSelectedTabIsVisible ();
847- } else {
848- validateScrollOffset ();
852+ scrollOffsetDirty = false ;
849853 }
854+ // ensure there's no gap between last visible tab and trailing edge
855+ validateScrollOffset ();
850856 }
851- isSelectingTab = false ;
852857
853858 Side tabPosition = getSkinnable ().getSide ();
854859 double tabBackgroundHeight = snapSize (prefHeight (-1 ));
@@ -981,20 +986,23 @@ private void updateHeaderClip() {
981986 private void addTab (Tab tab , int addToIndex ) {
982987 TabHeaderSkin tabHeaderSkin = new TabHeaderSkin (tab );
983988 headersRegion .getChildren ().add (addToIndex , tabHeaderSkin );
989+ invalidateScrollOffset ();
984990 }
985991
986992 private void removeTab (Tab tab ) {
987993 TabHeaderSkin tabHeaderSkin = getTabHeaderSkin (tab );
988994 if (tabHeaderSkin != null ) {
989995 headersRegion .getChildren ().remove (tabHeaderSkin );
990996 }
997+ invalidateScrollOffset ();
991998 }
992999
9931000 private void moveTab (int moveToIndex , TabHeaderSkin tabHeaderSkin ) {
9941001 if (moveToIndex != headersRegion .getChildren ().indexOf (tabHeaderSkin )) {
9951002 headersRegion .getChildren ().remove (tabHeaderSkin );
9961003 headersRegion .getChildren ().add (moveToIndex , tabHeaderSkin );
9971004 }
1005+ invalidateScrollOffset ();
9981006 }
9991007
10001008 private TabHeaderSkin getTabHeaderSkin (Tab tab ) {
@@ -1053,6 +1061,10 @@ public double getScrollOffset() {
10531061 return scrollOffset ;
10541062 }
10551063
1064+ public void invalidateScrollOffset () {
1065+ scrollOffsetDirty = true ;
1066+ }
1067+
10561068 private void validateScrollOffset () {
10571069 setScrollOffset (getScrollOffset ());
10581070 }
@@ -2241,6 +2253,7 @@ private void stopDrag() {
22412253 dragHeaderTransitionX = dragHeaderDestX - dragHeaderSourceX ;
22422254 dragHeaderAnim .playFromStart ();
22432255 }
2256+ tabHeaderArea .invalidateScrollOffset ();
22442257 }
22452258
22462259 private void reorderTabs () {
@@ -2294,4 +2307,16 @@ void test_disableAnimations() {
22942307 closeTabAnimation .set (TabAnimation .NONE );
22952308 openTabAnimation .set (TabAnimation .NONE );
22962309 }
2310+
2311+ double test_getHeaderAreaScrollOffset () {
2312+ return tabHeaderArea .getScrollOffset ();
2313+ }
2314+
2315+ void test_setHeaderAreaScrollOffset (double offset ) {
2316+ tabHeaderArea .setScrollOffset (offset );
2317+ }
2318+
2319+ boolean test_isTabsFit () {
2320+ return tabHeaderArea .tabsFit ();
2321+ }
22972322}
0 commit comments