JavaFX:'禁用'TableView行和列

时间:2016-05-13 09:20:13

标签: java javafx javafx-8

我有一个TableView,希望允许用户禁用单个行和列。

表数据由API提供,因此直到运行时才知道确切的行数和列数,但通常是4-30行和15-25列。理想情况下,第一列/行将是一个标题,最后一个将是一个页脚(即:对其上方/侧面的数据的摘要)。一旦用户执行了其他操作,他们应该能够禁用行或列 - 最好通过单击标题 - 然后从摘要中删除这些数据。

行/列应该仍然可见。不需要排序。不需要编辑。

我知道JavaFX只支持列标题,而不是行标题,当然也不支持任何页脚。这让我认为最好的选择是:

    完全
  • Remove the TableView headers
  • 将第一列和最后一列/行设置为页眉/页脚。
  • setCellSelectionEnabled为true
  • 如果所选单元格是标题单元格,则“禁用”该行或列;可能是通过CSS样式和从摘要中删除单元格值的组合。
  • 如果所选单元格不是标题单元格,请执行其他操作。
  • 如果再次单击标题单元格,请重新启用行或列。

这是最好的方法吗?是否有任何第三方库可以使工作更轻松?它甚至值得完全转储TableView并使用GridPane?

谢谢。

1 个答案:

答案 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但我找不到任何其他方式只注册一次事件处理程序,同时确保它实际上有效。

欢迎提出改进意见和建议。如果有更好的想法,我会在接受自己的答案前几天离开。