Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8091249

[VirtualFlow] VirtualFlow.show(int index) causes hopping when cell length exceeds the viewport length

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • None
    • javafx

      Calling VirtualFlow.show(int index) repeatedly to show a cell whose length exceeds the viewport length causes this cell to hop up and down.

      Here is the code to reproduce that behavior:


      import javafx.application.Application;
      import javafx.scene.Node;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Label;
      import javafx.scene.control.ListCell;
      import javafx.scene.control.ListView;
      import javafx.scene.layout.VBox;
      import javafx.scene.shape.Rectangle;
      import javafx.stage.Stage;

      import com.sun.javafx.scene.control.skin.VirtualFlow;

      public class VirtualFlowHopping extends Application {

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

          @Override
          public void start(Stage stage) throws Exception {
              ListView<Void> listView = new ListView<>();
              listView.setCellFactory(lv -> new BigCell());
              listView.getItems().add(null);

              Button hopBtn = new Button("VirtualFlow.show(0)");
              hopBtn.setOnAction(evt -> virtualFlowOf(listView).show(0));

              VBox root = new VBox(hopBtn, listView);
              stage.setScene(new Scene(root, 200, 300));
              stage.show();
          }

          // the only point of a BigCell is to be taller than the height of ListView
          private static class BigCell extends ListCell<Void> {
              private final Node graphic = new VBox(
                      new Label("Cell start"),
                      new Rectangle(100, 400),
                      new Label("Cell end"));

              @Override
              protected void updateItem(Void item, boolean empty) {
                  super.updateItem(item, empty);
                  if(empty) {
                      setText(null);
                      setGraphic(null);
                  } else {
                      setText(null);
                      setGraphic(graphic);
                  }
              }
          }

          private static <T> VirtualFlow<ListCell<T>> virtualFlowOf(ListView<T> lv) {
              for(Node child: lv.getChildrenUnmodifiable()) {
                  if(child instanceof VirtualFlow)
                      return (VirtualFlow<ListCell<T>>) child;
              }
              return null;
          }
      }


      Just click the button repeatedly to see the cell hopping.

      I realize that VirtualFlow is not part of the public API. Though I'm using it in my RichTextFX project to bring the paragraph with the caret to the viewport. The reported behavior causes trouble when the paragraph exceeds the viewport.

      I propose the following change to VirtualFlow.show(T cell) to fix this problem (not tested):

      Original code:

                  if (start < 0) {
                      adjustPixels(start);
                  } else if (end > viewportLength) {
                      adjustPixels(end - viewportLength);
                  }

      New code:

                  if (start < 0 && end < viewportLength) {
                      adjustPixels(Math.max(start, end - viewportLength));
                  } else if (end > viewportLength && start > 0) {
                      adjustPixels(Math.min(end - viewportLength, start));
                  }

            Unassigned Unassigned
            tmikula Tomas Mikula
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Imported: