使用JavaFX表格进行数据展示时,想要将当前所选择的单元格所在的行进行高亮,经过研究,实现方案见下文。
主要的思路:为Table定制TableCell,在TableCell中的RowIndex发生变更后,检查Cell所在行是否被选中,根据是否选中来设置单元格的背景色。
但按这种方式有一个问题,TableCell的RowIndex时,一般只有表格的数据发生变化的时候才会变更,如果直接在监听RowIndex的变更事件,并在其中进行处理,实际上点击某个单元格的时候是不会触发这部分处理逻辑的。很自然的,又想到监听表格的选择事件发生后去进行检查并处理,但矛盾的是,在表格的点击事件中又没法修改所选择的TableCell的背景色。
最终采取了一种折中的方式:在RowIndex变更事件中,对表格的选择事件进行监听,判断选择行中是否包含有当前Cell所在的行,根据检查结果设置单元格背景色。
关键代码如下(其中MapTable是继承自TableView的一个子类):
public class DragSelectionCell extends TextFieldTableCell<Map<String, Object>, String> {
public DragSelectionCell() {
super(new DefaultStringConverter());
setOnDragDetected(e -> {
startFullDrag();
startRow.setValue(getIndex());
startCol.setValue(getTableColumn());
});
setOnMouseDragEntered(event -> {
endRow.setValue(getIndex());
endCol.setValue(getTableColumn());
getTableView().getSelectionModel().clearSelection();
getTableView().getSelectionModel().selectRange(startRow.getValue(), startCol.getValue(), endRow.getValue(), endCol.getValue());
});
// 对行的index进行监听,如果index发生变更,则监听表格的选择事件,当选择的行发生变化时,修改当前行的背景色
this.tableRowProperty().addListener((observable, oldValue, newValue) ->
MapTable.this.getSelectionModel().getSelectedCells().addListener((ListChangeListener<? super TablePosition>) l -> {
ObservableList<? extends TablePosition> list = l.getList();
List<Integer> rowList = list.stream().map(TablePosition::getRow).collect(Collectors.toList());
if (rowList.contains(newValue.getIndex())) {
if (this.isSelected()) {
this.setBackground(new Background(new BackgroundFill(Color.valueOf("#0C739F"), null, null)));
} else {
this.setBackground(new Background(new BackgroundFill(Color.LIGHTGRAY, null, null)));
}
} else {
this.setBackground(null);
}
}));
}
}
然后在MapTable中,创建列的时候指定新列的TableCell:
private TableColumn<Map<String, Object>, String> createColumn(String title, double prefWidth, double maxWidth) {
TableColumn<Map<String, Object>, String> tableColumn = new TableColumn<>(title);
tableColumn.setCellValueFactory