正如@傑克斯指出的那樣,似乎並沒有一個捷徑。所以這裏是我解決問題的方法。
首先,我們hide the table header並允許單獨選擇單元格。 updateTable()
方法每n秒;它模擬了一個ScheduledService
API調用。 MyRow
對象只是一個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
對象之間的行/列,並更新CSS:
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");
}
}
它的工作原理,我主要是喜歡它。包含hasEventHandler
布爾值並不理想:它看起來有點冒險,但我無法找到任何其他註冊事件處理程序的方法,只能確保其實際工作。
歡迎提出意見和改進建議。如果有更好的想法,我會在接受我自己的答案前幾天離開它。
你看過函數'setRowFactory'(來自TableView)和'setCellFactory'(來自TableColumn)嗎?網上有很多例子,它允許程序員通過設置監聽器來定製單元/列行爲。由此,例如,如果點擊列/單元格,則可以執行操作。 – Jacks
我見過這些。我的問題可能應該包括對他們的引用,因爲如果沒有某種捷徑,那麼這兩種方法可能是必不可少的。 – AJR
據我所知,沒有真正的「捷徑」。只要舉一個這些函數的例子並重寫'call()'函數就可以根據需要創建單元格或列。您還可以在設置工廠時添加監聽器,以便在您的單元格(或單元格內的單元格,或者單元格內的單元)被單擊時觸發某個操作。希望這有助於,如果沒有,我可以給你一個小例子。 – Jacks