Marcelo Juventino
Marcelo Juventino

Reputation: 335

Javafx Bug? Tableview is not rendering correctly some rows

Actually I have a problem in my JavaFX app using TableView. I don't no why but, when I load data to TableView during runtime, the JavaFX is not rendering some rows, as you can see in the picture bellow:

enter image description here

But, when I resize the column, the data is displayed:

enter image description here

Bellow follow the source code used:

public void loadData()
{   
    // Define the TableView columns using Reflection defined by ResultSetMetadata
    ArrayList<TableColumn> gridColumns = defineGridColumns(data.get(0));
    this.tableView.getColumns().clear();
    this.tableView.getColumns().addAll(gridColumns);

    // Load data to TableView
    this.tableView.setItems(FXCollections.observableArrayList(data));
}

private void defineGridColumns(Object singleData)
{
    ArrayList<TableColumn> gridColumns = new ArrayList<>();

    Field[] fields = singleData.getClass().getFields();
    for (int i = 0; i < fields.length; i++)
    {
        TableColumn column = createTableColumn(fields[i].getName());
        this.gridColumns.add(column);
    }

    return gridColumns;
}

private TableColumn createTableColumn(String columnName)
{
    TableColumn column = new TableColumn(columnName);
    column.setCellValueFactory(new PropertyValueFactory(columnName));
    column.setPrefWidth(columnName.length() * 20);

    HBox box = new HBox();
    box.setAlignment(Pos.CENTER);
    box.prefWidthProperty().bind(column.widthProperty().subtract(5));
    box.setSpacing(10.0);
    box.getChildren().addAll(new Label(column.getText()));
    column.setGraphic(box);

    // Align the cell content in center
    column.setCellFactory(new Callback<TableColumn, TableCell>()
    {
        @Override
        public TableCell call(TableColumn param)
        {
            TableCell cell = new TableCell()
            {
                @Override
                public void updateItem(Object item, boolean empty)
                {
                    if (item != null)
                    {
                        setText(item.toString());
                    }
                }
            };
            cell.setAlignment(Pos.CENTER);
            return cell;
        }
    });

    return column;
}   

Well, what I'm doing wrong? I already update my Java to the lastest version (JDK 1.8.11).

Thanks to everybody!


Palliative Solution

As resizing column width triggers JavaFX to display the data, I did a method that changes all columns sizes after the data is loaded:

public void loadData()
{   
    // Define the TableView columns using Reflection defined by ResultSetMetadata
    ArrayList<TableColumn> gridColumns = defineGridColumns(data.get(0));
    this.tableView.getColumns().clear();
    this.tableView.getColumns().addAll(gridColumns);

    // Load data to TableView
    this.tableView.setItems(FXCollections.observableArrayList(data));

    // HACK to force JavaFX display all data
    final TrendAnalysisTabController thisController = this;
    Platform.runLater(new Runnable()
    {
        @Override
        public void run()
        {
            thisController.adjustAllColumnWidths();
        }
    });
}

private void adjustAllColumnWidths()
{
    TableViewSkin<?> skin = (TableViewSkin<?>) this.tableView.getSkin();
    TableHeaderRow headerRow = skin.getTableHeaderRow();
    NestedTableColumnHeader rootHeader = headerRow.getRootHeader();
    for (TableColumnHeader columnHeader : rootHeader.getColumnHeaders())
    {
        try
        {
            TableColumn<?, ?> column = (TableColumn<?, ?>) columnHeader.getTableColumn();
            if (column != null)
            {
                // Changes the width column and rollback it
                double prefWidth = column.getPrefWidth();
                column.setPrefWidth(prefWidth + 0.01);
                column.setPrefWidth(prefWidth);
            }
        }
        catch (Throwable e)
        {
            log.log(Level.SEVERE, "Error adjusting columns widths: " + e.getMessage(), e);
        }
    }
}

Upvotes: 1

Views: 2705

Answers (2)

Jonathan Millman
Jonathan Millman

Reputation: 165

because TableCells are reused, you need to explicitly "clear" them in your updateItem method:

@Override
public void updateItem(Object item, boolean empty)   {
   super.updateItem(item, empty);
   if (item == null || empty)   {
       setText(null);
   } else{
        setText(item.toString());
   }
}

Upvotes: 5

James_D
James_D

Reputation: 209684

I'm not sure if this fixes your problem, but when creating a TableCell implementation, your updateItem(...) method must call super.updateItem(...):

 column.setCellFactory(new Callback<TableColumn, TableCell>()
    {
        @Override
        public TableCell call(TableColumn param)
        {
            TableCell cell = new TableCell()
            {
                @Override
                public void updateItem(Object item, boolean empty)
                {
                    // Don't omit this:
                    super.updateItem(item, empty);
                    if (item != null)
                    {
                        setText(item.toString());
                    }
                }
            };
            cell.setAlignment(Pos.CENTER);
            return cell;
        }
    });

Upvotes: 1

Related Questions