Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Tuesday, February 16, 2016

Capturing a Faux Scrolling Event in a JavaFX ListView

ListView and TableView scrolling in JavaFX 8 can't be customized by developers.  Although these components inherit ScrollEvent methods from the Node class, registering handlers on onScrollStart, onScroll, and onScrollFinished don't do anything.  You can't publicly access the ScrollBar object either.

This bug report seems to describe the design decisions around encapsulating the scrollbar object and events.

This post shows how you can fake a ScrollEvent by keying off of the layoutY property of an individual ListCell.  ListCells can be recycled, so I put a handler on each of the ListCells and interrogate the data value to determine which one is the last item.

The use case for this is to load the ListView and fetch data once the last item is encountered.

This is a real hack, but it's using public APIs.

public class LVSApp extends Application {

    private final static Integer LAST_ITEM = 199;

    @Override
    public void start(Stage primaryStage) throws Exception {

        VBox vbox = new VBox();

        ListView<Integer> lv = new ListView<>();

        lv.setCellFactory((i) ->
            new ListCell<Integer>() {

                private ChangeListener listener = (obs, ov, nv) -> {
                    if( getText() != null
                       && getText().equals(String.valueOf(LAST_ITEM))
                       && ((getListView().getHeight()-this.getHeight()
                             -nv.doubleValue()) > 0 )) {
                        System.out.println("last item in view " +
                           " scrolled into view (fetch more data?)");
                    }
                };

                {
                    layoutYProperty().addListener(listener);
                }

                @Override
                protected void finalize() throws Throwable {
                    super.finalize();
                    layoutYProperty().removeListener(listener);
                }

                @Override
               protected void updateItem(Integer item, boolean empty) {
                   if( item != null && !empty ) {
                       setText( String.valueOf(item) );
                   } else {
                       setText( "" );
                   }
               }
           }
        );

    for( int i=0; i<200; i++ ) {
            lv.getItems().add(new Integer(i));
        }
        vbox.getChildren().add( lv );

        Scene scene = new Scene(vbox);

        primaryStage.setScene( scene );
        primaryStage.show();
    }

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

No comments:

Post a Comment