How to correctly add new data to TableView and scroll to it
Asked Answered
D

3

10

Problem

I want to add data dynamically to a TableView and scroll to the new data's position. But when the rows in the TableView reach the ViewPort size, I get this in the console:

Apr 18, 2015 9:14:34 AM com.sun.javafx.scene.control.skin.VirtualFlow addTrailingCells INFO: index exceeds maxCellCount. Check size calculations for class javafx.scene.control.TableRow

So I guess I did something wrong. All I did was using the Oracle TableView example and add this:

// button to add new data
Button bt = new Button( "Add");
bt.setOnAction(e -> {

    // insert new item
    int i = data.size() + 1;
    Person person = new Person( "Name " + i, "Name " + i, "Mail " + i);
    data.add( person);

    // scroll to new item
    table.scrollTo( person);

});

The same happens when you use

    table.getItems().add( person);

instead of modifying the list.

The culprit is the scrollTo method. The same info/error occurs when you use the row index with the scrollTo method.

Question

How do you add new items correctly to a TableView, so that the info/error doesn't show up?

Code

Here's a full example. The table is pre-filled. If you hit the Add button the viewport size is reached and the info (or error?) is displayed in the console.

public class TableViewSample extends Application {

    private TableView<Person> table = new TableView<Person>();
    private final ObservableList<Person> data = FXCollections.observableArrayList();

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

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(500);

        table.setEditable(true);

        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
                new PropertyValueFactory<Person, String>("firstName"));

        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<Person, String>("lastName"));

        TableColumn emailCol = new TableColumn("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
                new PropertyValueFactory<Person, String>("email"));

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);

        // -------------------------------
        // dynamically add data
        // -------------------------------

        // fill table with data
        for( int i=0; i < 14; i++) {
            Person person = new Person( "Name " + i, "Name " + i, "Mail " + i);
            data.add( person);
        }

        // button to add new data
        Button bt = new Button( "Add");
        bt.setOnAction(e -> {

            // insert new item
            int i = data.size() + 1;
            Person person = new Person( "Name " + i, "Name " + i, "Mail " + i);
            data.add( person);

            // scroll to new item
            table.scrollTo( person);

        });

        // -------------------------------

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.getChildren().addAll(table, bt);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();


    }

    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;

        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }

        public String getEmail() {
            return email.get();
        }

        public void setEmail(String fName) {
            email.set(fName);
        }
    }
} 
Diannediannne answered 18/4, 2015 at 7:21 Comment(4)
Do you want to scroll always to the bottom of the TableView?Rodolforodolph
No, there may be use cases in which the new row isn't at the bottom. Example: Focus is on row 5, user scrolls down to row 100. Row 5 isn't visible. User presses "insert" button. Row should be added at position 6 and the table should be scrolled to that new row.Diannediannne
Seems like a bug to me, as this only happens as long as the TableView contains no ScrollBars.Goings
@Roland, seems like this issue persists in new Java versions (8_51) and the Jira Bug Tracker is about to be removed from that site. I'll recommend you to update that issue request to somewhere else.Sampling
S
4

I solved this problem using fixed cells..

listCategory.setFixedCellSize(40); 

or

-fx-fixed-cell-size : 40;
Servitor answered 24/1, 2019 at 15:14 Comment(3)
I am facing the issue, that beside showing the unhelpful addTrailingCells logmessage, the listview loads sometimes really slow but mostly fine. Setting the fixed cell size helped for that issue too. With that it loads at constant speed without logmessage.Myron
Hi yes, the virtual flow in list-view does calculations fixed.. it's don't calculate new values when you modify a size from inner cells.. then fixed cell size works.. if you need this.. try to use flowless this lib is very good.. regards.Servitor
This fixed my issue, no longer getting that error, thanks!Demount
P
0

I dont find a solution but the problem is not about using scrollTo() method it's always happen when you're scroll to bottom (even manually) and increase the window height when the scroll disappear i don't know why need to open a bug ticket

Pterous answered 15/5, 2016 at 11:22 Comment(1)
This will scroll to the bottom of the list. The original problem was to scroll to a specific row.Marconigraph
K
-1

Suppress the warning by resetting the log manager:

import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.*;
import javafx.beans.property.*;
import javafx.collections.*;

import java.util.logging.LogManager;

public class TableViewSample extends Application {
  // ... setup ...

  public static void main(String[] args) {

    // Suppress the warning message when the Add button is clicked.
    LogManager.getLogManager().reset();

    launch(args);
  }

This will affect the entire application's logger. If that is not desired, change the logging level for the offending class (com.sun.javafx.scene.control.skin.VirtualFlow) to Level.OFF.

See also:

Since this is a warning message, it can probably be ignored, and therefore suppressed. As far as I can tell, the new row is added successfully. Here is the offending code that was checked in, which, IMO, violates the principle of least astonishment:

Kellerman answered 5/1, 2017 at 2:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.