ControlsFX横向冻结Map<String,Object> 的tableView
时间: 2023-11-18 19:20:06 浏览: 78
ControlsFX提供了一个名为"FreezePane"的组件,可以用于横向和纵向冻结JavaFX中的TableView。但是,FreezePane只支持单一列的冻结,而不支持Map<String,Object>这种复合数据类型的冻结。解决这个问题的方法是自定义一个TableView,并在其中添加多个FreezePane组件来实现横向和纵向冻结。以下是一个简单的示例代码:
```java
public class FrozenTableView extends TableView<Map<String, Object>> {
private FreezePane rowHeader;
private FreezePane columnHeader;
private ObservableList<Map<String, Object>> data;
public FrozenTableView() {
super();
data = FXCollections.observableArrayList();
setItems(data);
rowHeader = new FreezePane();
columnHeader = new FreezePane();
setFixedCellSize(25); // 设置每行行高
// 监听TableView的滚动事件,同步rowHeader和columnHeader的滚动位置
addEventFilter(ScrollEvent.SCROLL, event -> {
rowHeader.setHvalue(getHvalue());
columnHeader.setVvalue(getVvalue());
});
// 监听TableView的宽高变化事件,更新rowHeader和columnHeader的宽高
widthProperty().addListener((observable, oldValue, newValue) -> {
rowHeader.setPrefWidth(newValue.doubleValue());
columnHeader.setPrefWidth(newValue.doubleValue());
});
heightProperty().addListener((observable, oldValue, newValue) -> {
rowHeader.setPrefHeight(newValue.doubleValue() - 25);
columnHeader.setPrefHeight(newValue.doubleValue() - 25);
});
// 监听TableView的数据变化事件,同步更新rowHeader和columnHeader的数据
data.addListener((ListChangeListener<Map<String, Object>>) c -> {
while (c.next()) {
if (c.wasAdded()) {
for (int i = 0; i < c.getAddedSize(); i++) {
rowHeader.addRow(c.getAddedSubList().get(i), i);
}
} else if (c.wasRemoved()) {
for (int i = 0; i < c.getRemovedSize(); i++) {
rowHeader.removeRow(c.getRemoved().get(i));
}
}
}
});
// 设置行头和列头
setRowFactory(tv -> {
TableRow<Map<String, Object>> row = new TableRow<>();
row.itemProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
rowHeader.addHeaderRow(row.getIndex());
}
});
return row;
});
setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
getColumns().addListener((ListChangeListener<TableColumn<Map<String, Object>, ?>>) c -> {
while (c.next()) {
if (c.wasAdded()) {
for (int i = 0; i < c.getAddedSize(); i++) {
TableColumn<Map<String, Object>, ?> col = c.getAddedSubList().get(i);
columnHeader.addColumn(col, i);
}
} else if (c.wasRemoved()) {
for (int i = 0; i < c.getRemovedSize(); i++) {
TableColumn<Map<String, Object>, ?> col = c.getRemoved().get(i);
columnHeader.removeColumn(col);
}
}
}
});
}
public void setData(ObservableList<Map<String, Object>> data) {
this.data = data;
setItems(data);
rowHeader.clearRows();
columnHeader.clearColumns();
setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
getColumns().addListener((ListChangeListener<TableColumn<Map<String, Object>, ?>>) c -> {
while (c.next()) {
if (c.wasAdded()) {
for (int i = 0; i < c.getAddedSize(); i++) {
TableColumn<Map<String, Object>, ?> col = c.getAddedSubList().get(i);
columnHeader.addColumn(col, i);
}
} else if (c.wasRemoved()) {
for (int i = 0; i < c.getRemovedSize(); i++) {
TableColumn<Map<String, Object>, ?> col = c.getRemoved().get(i);
columnHeader.removeColumn(col);
}
}
}
});
}
}
```
这个自定义的TableView使用了两个FreezePane组件来实现行和列的冻结,其中rowHeader用于显示行头,columnHeader用于显示列头。在setData方法中,我们可以将需要显示的Map<String,Object>数据集合传入,并将其设置为TableView的数据源。同时,我们也需要更新rowHeader和columnHeader的数据。在自定义的TableView中,我们还需要监听TableView的宽高变化事件和数据变化事件,并在发生变化时同步更新rowHeader和columnHeader的宽高和数据。最后,在自定义的TableView中,我们也需要设置行头和列头,以便在rowHeader和columnHeader中显示行和列的标题。
阅读全文