我有一个TableView,希望允许用户禁用单个行和列。
表数据由API提供,因此直到运行时才知道确切的行数和列数,但通常是4-30行和15-25列。理想情况下,第一列/行将是一个标题,最后一个将是一个页脚(即:对其上方/侧面的数据的摘要)。一旦用户执行了其他操作,他们应该能够禁用行或列 - 最好通过单击标题 - 然后从摘要中删除这些数据。
行/列应该仍然可见。不需要排序。不需要编辑。
我知道JavaFX只支持列标题,而不是行标题,当然也不支持任何页脚。这让我认为最好的选择是:
这是最好的方法吗?是否有任何第三方库可以使工作更轻松?它甚至值得完全转储TableView并使用GridPane?
谢谢。
答案 0 :(得分:1)
正如@Jacks指出的那样,似乎并没有这样的捷径。所以这就是我如何解决问题的方法。
首先,我们hide the table header并允许单独选择单元格。每 n 秒调用ScheduledService
方法;它模拟MyRow
API调用。 ObservableList<TableCell>
对象只是COLUMN_HEADER, ROW_FOOTER
的包装器,我们使用它,因为我们不知道在运行时之前会有多少列。
private void updateTable() {
Pane header = (Pane) myTable.lookup("TableHeaderRow");
header.setVisible(false);
myTable.getSelectionModel().setCellSelectionEnabled(true);
myTable.setLayoutY(-header.getHeight());
myTable.autosize();
List<MyRow> list = new CopyOnWriteArrayList();
Integer maxRows = 5, maxColumns = 5; // For example
MyRow row;
for (int rowId = 0; rowId <= maxRows; rowId++) {
Boolean isEmpty = myTable.getColumns().isEmpty();
row = new MyRow();
Integer total = 0;
for (int colId = 0; colId <= maxColumns; colId++) {
if (isEmpty) {
myTable.getColumns().add(createReactiveColumn());
}
TableCell cell = new MyTableCell();
if (rowId == 0 && colId == 0) {
// Top-left cell
} else if (rowId == 0) {
// Column title
cell.setUserData(COLUMN_HEADER);
cell.setText("CH" + Integer.toString(colId));
} else if (colId == 0) {
// Row title
cell.setUserData(ROW_HEADER);
cell.setText("RH" + Integer.toString(rowId));
} else if (colId == maxColumns) {
// Row 'footer'
cell.setUserData(ROW_FOOTER);
cell.setText(Integer.toString(total));
} else if (rowId == maxRows) {
// Column 'footer'
cell.setUserData(COLUMN_FOOTER);
cell.setText("CF" + Integer.toString(rowId));
} else {
// Data
Integer r = new Random().nextInt(9); // Simulate API data
if (!this.disabledColumns.contains(myTable.getColumns().get(colId))) {
total += r; // Sum of each enabled cell
}
cell.setUserData(DATA);
cell.setText(Integer.toString(r));
}
row.add(cell);
}
list.add(row);
}
myTable.getItems().setAll(list);
}
等是枚举。
TableColumn
setCellFactory()
只使用private TableColumn<MyRow, String> createReactiveColumn() {
TableColumn<MyRow, String> column = new TableColumn<MyRow, String>();
column.setCellFactory(new Callback<TableColumn<MyRow, String>, TableCell<MyRow, String>>() {
@Override
public TableCell<MyRow, String> call(TableColumn<MyRow, String> param) {
return new MyTableCell();
}
});
column.setSortable(FALSE);
column.setMinWidth(40d);
return column;
}
方法:
MyTableCell
MOUSE_CLICKED
添加了TableCell
事件处理程序,并复制了更新后的private class MyTableCell extends TableCell<MyRow, String> {
Boolean hasEventHandler = FALSE;
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty && getTableRow() != null && getTableRow().getItem() != null) {
MyRow er = (MyRow) getTableRow().getItem();
TableCell cell = er.get(getTableView().getColumns().indexOf(getTableColumn()));
this.setText(cell.getText());
if (cell.getUserData() instanceof MyTableCellEnum) {
MyTableCellEnumcellType = (MyTableCellEnum) cell.getUserData();
if (null != cellType && !hasEventHandler) {
switch (cellType) {
case COLUMN_HEADER:
addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
toggleColumn(getTableColumn());
}
});
hasEventHandler = TRUE;
break;
case ROW_HEADER:
addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
toggleRow(getTableRow());
}
});
hasEventHandler = TRUE;
break;
case DATA:
addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
// Do other action on selection
}
});
break;
default:
break;
}
}
}
}
}
}
中的文字。
TableRow
最后,切换方法只是在一组禁用的TableColumn
/ private void toggleRow(TableRow tableRow) {
if (this.disabledRows.contains(tableRow)) {
this.disabledRows.remove(tableRow);
tableRow.getStyleClass().remove("cell-disabled");
} else {
this.disabledRows.add(tableRow);
tableRow.getStyleClass().add("cell-disabled");
}
}
private void toggleColumn(TableColumn tableColumn) {
System.out.println(tableColumn);
if (this.disabledColumns.contains(tableColumn)) {
this.disabledColumns.remove(tableColumn);
tableColumn.getStyleClass().remove("cell-disabled");
} else {
this.disabledColumns.add(tableColumn);
tableColumn.getStyleClass().add("cell-disabled");
}
}
对象之间交换行/列并更新CSS:
hasEventHandler
它很有效,我对它很满意。包含$(document).ready(function(){
$('input.form-control').focus(function(e) {
$(this).prev('span').hide(); // use hide() for hiding
});
});
布尔值并不理想:看起来有点hacky但我找不到任何其他方式只注册一次事件处理程序,同时确保它实际上有效。
欢迎提出改进意见和建议。如果有更好的想法,我会在接受自己的答案前几天离开。