bgbgtata
bgbgtata

Reputation: 3

Get the location of a tableview cell in JavaFX

new to JavaFX, and been trying to get a TableView cell's position by row, col indices. Looking for something like Swing's JTable.getCellRect;

I've seen solutions for the case where a specific cell's value is needed, (JavaFX Simplest way to get cell data using table index)

I've also figured it would be enough to get the TableCell of the corresponding row and column, then get bounds and use localToScreen etc, but couldn't find a way to get a specific table-cell as well.

Would love any help with any of that. Thanks in advance

Upvotes: 0

Views: 3443

Answers (1)

James_D
James_D

Reputation: 209330

There's no direct way to do this in JavaFX, by design. Since cells are only created for data that is currently visible, and are reused (for example as the user scrolls around the table), there isn't a 1-1, or even a consistent, relationship between any given cell and the "location" in the table's backing data. Consequently, you really should not even attempt to find a cell for a given data item, and should try to find another approach to whatever you are trying to do.

(From a MVC design approach, this makes sense too: you are asking to find the view (cell) from the model (data); the model is supposed to be completely unaware of the view.)

If you really want to attempt this (and, in case it's not clear, I think you should find another approach), you can try to keep track of the cells for each position as they change, using something like the following:

TableView<SomeDataType> table = new TableView<>();

Map<TableColumn<SomeDataType, ?>, Map<Number, TableCell<SomeDataType, ?>>> cells = new HashMap<>();

TableColumn<SomeDataType, SomeColumnDataType> column = new TableColumn<>(...);
cells.put(column, new HashMap<>();

column.setCellValueFactory(...);

column.setCellFactory(tc -> {
    TableCell<SomeDataType, SomeColumnDataType> cell = new TableCell<SomeDataType, SomeColumnDataType>() {
        @Override
        protected void updateItem(SomeColumnDataType item, boolean empty) {
            super.updateItem(item, empty) ;
            if (empty) {
                setText(null);
            } else {
                setText(item.toString());
            }
        }
    };

    cell.indexProperty().addListener((obs, oldIndex, newIndex) -> {
        if (oldIndex != null) {
            cells.get(column).remove(oldIndex);
        }
        if (newIndex != null && newIndex.intValue() != -1) {
            cells.get(column).put(newIndex, cell);
        }
    });

    return cell ;
});

// repeat for other columns...

Then you can do

TableCell<SomeDataType, ?> cell = cells.get(someColumn).get(someIndex);

to get a cell for a specific column and row index. Note that you need to check for null (if that data doesn't currently have a cell).

This will probably need very careful debugging, but the approach should work.

Update: I made an SSCCE using this technique here.

You could also try via a lookup. Lookups are not very robust, and won't work at all until CSS has been applied to the scene graph, but you can try something like this:

TableColumn<...> columnOfInterest = ... ;
int rowIndexOfInterest = ... ;

TableCell<?, ?> cell = null ;
for (Node n : table.lookupAll(".table-cell")) {
    TableCell<?,?> c = (TableCell<?,?>) n ;
    if (c.getTableColumn() == columnOfInterest 
            && c.getIndex() == rowIndexOfInterest) {
        cell = c ;
        break ;
    }
}

if (cell != null) {
    // ...
}

or in a more Java 8 approach:

table.lookupAll(".table-cell").stream()
    .map(TableCell.class::cast)
    .filter(c -> c.getTableColumn() == columnOfInterest && c.getIndex() == rowIndexOfInterest)
    .findAny()
    .ifPresent(cell -> {
        // do whatever you need with the cell....
    });

Upvotes: 4

Related Questions