JDK-8255436 : ListView horizontal ScrollBar flickers when widest item is near top of viewport
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: openjfx11,openjfx14,openjfx15
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2020-10-23
  • Updated: 2022-02-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Duplicate :  
Description
ADDITIONAL SYSTEM INFORMATION :
JavaFX 15

A DESCRIPTION OF THE PROBLEM :
If a vertical ListView contains more items than the viewport can accommodate, and the widest item is near the top of the viewport, and the viewport is slightly too narrow to accommodate the widest item, then resizing the ListView by small amounts causes the horizontal ScrollBar to flicker between present and absent. This causes flickering vertical repositioning of all of the list items. 

Also, under some conditions, the ListView can enter an endless cycle of removing/adding the breadth ScrollBar while no inputs are changing. The attached source code triggers this condition. I was only able to trigger the condition when the ListCell's graphic is a Parent (suspecting that resizes of that graphic were triggering extra layout passes). I have a screen capture video of the behavior, but the bug report form does not seem to have an attachments feature.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached JavaFX application.
Then make some other application active, then make the JavaFX application active again.
I use Alt-Tab on Windows.
Within 2 or 3 switches of the active application, observe an endless cycle of adding/removing the horizontal ScrollBar.

If you stretch the application window vertically with the vertical ScrollBar at max value and the widest item near the top of the viewport, then you can observe the horizontal ScrollBar alternately added/removed even though the resize amount is much smaller than the height of that item.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The horizontal ScrollBar should remain stable (visible or not visible) if the list items, viewport size, vertical ScrollBar position, etc. do not change.

While dragging to resize the application window vertically, there should be one particular height at which the horizontal ScrollBar is added/removed.
ACTUAL -
The ListView can enter a state in which, with no changed inputs, the horizontal ScrollBar is endlessly added and removed, thus pushing the widest item out the top of the viewport and then bringing the widest item back into the top of the viewport.

While dragging to resize the application window vertically, while passing through a certain range of heights, the horizontal ScrollBar alternates between added/removed with each layout pass.

---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

/**
 * An example of ListView breadth ScrollBar endless jitter.
 **/
public class ListViewScrollBarJitterExample extends Application {

   public static void main( final String[] args ) {
      launch( args );
   }

   final ObservableList<String> items = FXCollections.observableArrayList(
         "X0.0 Echo management message",
         "X0.1 Common Time Reference (CTR) message",
         "X0.2 Round-Trip Time Delay message",
         "X0.3 JREAP J-Series Acknowledgement (Full Stack) message",
         "X0.4 JREAP J-Series Acknowledgement (Application) message",
         "X0.5 Latency Threshold message",
         "X0.6 Latency Exceeded message",
         "X0.7 Operator-to-Operator message",
         "X0.8 Special Event message",
         "X0.9 Terminate Link message",
         "X0.10 Remote Filter message",
         "X0.11 Secondary Track Number List message",
         "X0.12 Direct Connection List message",
         "X0.13 Network Connectivity Matrix message",
         "X0.14 Connectivity Feedback message"
   );

   final ListView<String> listView = new ListView<>( items );

   private static class MyListCell extends ListCell<String> {

      private final Button button1 = new Button( "Button" );

      private final Button button2 = new Button();

      private final HBox hBox = new HBox( button1, button2 );

      @Override
      protected void updateItem( final String item, final boolean empty ) {
         super.updateItem( item, empty );
         if( !empty ) {
            setText( null );
            button2.setText( item );
            setGraphic( hBox );
         } else {
            setText( null );
            setGraphic( null );
         }
      }
   }

   @Override
   public void start( final Stage primaryStage ) throws Exception {
      listView.setCellFactory( listView -> new MyListCell() );
      primaryStage.setScene( new Scene( listView ) );
      primaryStage.show();
      // Set the width, height, vertical scroll position, selection and focus to trigger the bug.
      primaryStage.setWidth( 435.3333435058594d );
      primaryStage.setHeight( 357.3333435058594d );
      Platform.runLater( () -> {
         listView.lookupAll( ".scroll-bar" ).stream().filter( node ->
               node instanceof ScrollBar ).map( node -> (ScrollBar) node ).filter( scrollBar ->
               scrollBar.getOrientation() == Orientation.VERTICAL ).findFirst().ifPresent( vsb -> {
            vsb.setValue( vsb.getMax() );
            listView.getSelectionModel().select( items.size() - 1 );
            listView.requestFocus();
            listView.getFocusModel().focus( items.size() - 1 );
         } );
      } );
   }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I implemented a ListCell that overrides computePrefWidth(height) to, if the ListView is VERTICAL, then returns the max computed width for its own list item and the item (if any) at the previous index.
This is a weak workaround because it must be used with each ListView. (Also, for some relative heights of horizontal ScrollBar vs. heights of ListCells, it might be necessary to include more than one previous item in the computation.)

FREQUENCY : always



Comments
Checked with attached testcase, Issue is reproducible in Windows 10 Test Result: ========= openjfx 11_0_2 : fail openjfx 15_ea_7: fail openjfx 16_ea_1: fail 8u261: Pass, did not observe flickering.
27-10-2020