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

TableView scrollTo() will not show last row for a custom cell factory.

    XMLWordPrintable

    Details

      Description

      A DESCRIPTION OF THE PROBLEM :
      When a custom cell factory used in a TableView to show wrapped text, the scrollTo() function will not show last row. The issue should be reproduceable with attached sample code below.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run attached source code. Added enough line of text to the table until vertical scroll bar shows. Then add long text lines so they will be wrapped in the table.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Show full line of last added text.
      ACTUAL -
      Last line will not show if there are wrapped text in the view of the TableView.

      ---------- BEGIN SOURCE ----------
      import javafx.application.Application;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.geometry.Insets;
      import javafx.geometry.Orientation;
      import javafx.geometry.Pos;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Control;
      import javafx.scene.control.Separator;
      import javafx.scene.control.TableCell;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.scene.control.TextField;
      import javafx.scene.control.cell.PropertyValueFactory;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.Priority;
      import javafx.scene.layout.VBox;
      import javafx.scene.text.Text;
      import javafx.stage.Stage;
      import javafx.util.Callback;

      /**
       * Issue with programmatic scroll in TableView with a custom cell factory.
       *
       *
       * This program emulates a chat application when everything typed in the bottom
       * text box is added to the end of a TableView above and scroll to show what is
       * just added by calling scrollTo().
       *
       * The "Text" column of TableView uses a custom cell factory of a Text control
       * to wrap text to accommodate long text value.
       *
       * It works well until a long text is added that cause text to wrap in the table,
       * then the text added will not be fully shown. It gets worse when there are multiple
       * wrapped texts in the view of the TableView. Calling refresh() will not resolve
       * the issue. It will be resolved either by manually scroll up and down, or until
       * all wrapped text scrolled out of the view of the TableView.
       *
       */

      public class TableViewScrollTest extends Application {

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

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

      // Create a two column table with a custom cell factory
      // to support wrapped text.
      _textTable = new TableView<>();
      _textTable.setEditable(false);
      _textTable.setSelectionModel(null);
              TableColumn<TextRow, String> nameColumn = new TableColumn<>("Name");
              nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
              nameColumn.setPrefWidth(100);
              nameColumn.setReorderable(false);
              nameColumn.setResizable(false);
              nameColumn.setSortable(false);
              nameColumn.setStyle("-fx-alignment: center");
              _textTable.getColumns().add(nameColumn);
              TableColumn<TextRow, String> textColumn = new TableColumn<>("Text");
              textColumn.setCellValueFactory(new PropertyValueFactory<>("text"));
              textColumn.setCellFactory(new Callback<TableColumn<TextRow, String>, TableCell<TextRow, String>>() {
                  @Override
                  public TableCell<TextRow, String> call(TableColumn<TextRow, String> param) {
                      TableCell<TextRow, String> cell = new TableCell<>();
                      Text text = new Text();
                      cell.setGraphic(text);
                      cell.setPrefHeight(Control.USE_COMPUTED_SIZE);
                      text.wrappingWidthProperty().bind(textColumn.widthProperty().subtract(20));
                      text.textProperty().bind(cell.itemProperty());
                      return cell;
                  }
              });
              textColumn.prefWidthProperty().bind(_textTable.widthProperty().subtract(100));
              textColumn.setReorderable(false);
              textColumn.setResizable(false);
              textColumn.setSortable(false);
               _textTable.getColumns().add(textColumn);
              _textList = FXCollections.observableArrayList();
              _textTable.setItems(_textList);

      Separator separator = new Separator();
      separator.setOrientation(Orientation.HORIZONTAL);

      // Input text field and a button to add the text.
      HBox hBox = new HBox(20);
      hBox.setAlignment(Pos.CENTER);
      _textField = new TextField();
      Button button = new Button("Send");
      button.setDefaultButton(true);
      button.setOnAction(e -> addText());
      HBox.setHgrow(_textField, Priority.ALWAYS);
      hBox.getChildren().addAll(_textField, button);

      VBox vBox = new VBox(15);
      vBox.setPadding(new Insets(20, 10, 20, 10));
      VBox.setVgrow(_textTable, Priority.ALWAYS);
      vBox.getChildren().addAll(_textTable, separator, hBox);

      Scene scene = new Scene(vBox);
      primaryStage.setScene(scene);
      primaryStage.setTitle("TableView Scroll Test");
      primaryStage.setMinWidth(400);
      primaryStage.setWidth(400);
      primaryStage.setMinHeight(400);
      primaryStage.setHeight(400);
      primaryStage.show();

      _textField.requestFocus();
      }

      private void addText() {
      String t = _textField.getText().strip();
      if (!t.isEmpty()) {
      TextRow row = new TextRow("My Name", t);
      _textList.add(row);

      _textTable.refresh(); // This will not help.

      // The "scroll to last row" below will not work well when
      // there are wrapped text line in the view of the TableView.
      _textTable.scrollTo(_textList.size() - 1);
      }
      _textField.setText("");
      }

      public static class TextRow {

      public String getName() {
      return _name;
      }

      public String getText() {
      return _text;
      }

      private TextRow(String name, String text) {
      _name = name;
      _text = text;
      }

      private final String _name;
      private final String _text;
      }

          private TableView<TextRow> _textTable;
      private ObservableList<TextRow> _textList;
          private TextField _textField;
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Manually scroll up first and then down will show the last line.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              pnarayanaswa Praveen Narayanaswamy
              Reporter:
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: