我正在使用一个自定义的可编辑表单元格工厂,我已经工作了一段时间。我目前正在实现一个功能,允许单击开始编辑。
我有一个点击开始单元格编辑,但是如果你点击另一个单元格一次,以前的不关闭。我的想法是在打开点击单元格进行编辑之前,循环遍历调用cancelEdit()
的所有单元格。
下面是我正在使用的整个单元格类(双击编辑即可)。我正在处理的部分在构造函数中。
public class EditingCell<S, T> extends TableCell<S, T> {
private TextField textField;
public EditingCell() {
TableView<S> table = this.getTableView();
addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
for(TableColumn<S, ?> col : table.getColumns()) {
// cancelEdit() on all cells here
}
startEdit();
}
});
}
public void commit(Object val) {
commit(val, this.getTableRow().getIndex(), getTableView().getColumns().indexOf(this.getTableColumn()));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void commit(Object val, int row, int col) {
// Get the table
TableView<S> t = this.getTableView();
// Get the selected row/column
S selectedRow = t.getItems().get(row);
if (selectedRow == null)
return;
TableColumn<S, ?> selectedColumn = t.getColumns().get(col);
// Get current property name
String propertyName = ((PropertyValueFactory) selectedColumn.getCellValueFactory()).getProperty();
// Create a method name conforming to java standards ( setProperty )
propertyName = ("" + propertyName.charAt(0)).toUpperCase() + propertyName.substring(1);
// Try to run the update
try {
// Type specific checks - could be done inside each
// setProperty() method
if (val instanceof Double) {
Method method = selectedRow.getClass().getMethod("set" + propertyName, double.class);
method.invoke(selectedRow, (double) val);
}
if (val instanceof String) {
Method method = selectedRow.getClass().getMethod("set" + propertyName, String.class);
method.invoke(selectedRow, (String) val);
}
if (val instanceof Integer) {
Method method = selectedRow.getClass().getMethod("set" + propertyName, int.class);
method.invoke(selectedRow, (int) val);
}
} catch (Exception e) {
e.printStackTrace();
}
// CommitEdit for good luck
commitEdit((T) val);
TableUtils.Refresh(t, t.getItems());
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
String val = "0.0";
if (!textField.getText().equals(""))
val = "" + Double.parseDouble(textField.getText());
setText(NumberUtils.roundTo2(NumberUtils.parseDouble(val)) + "");
setGraphic(null);
}
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText("");
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(NumberUtils.roundTo3(NumberUtils.parseDouble(getString())) + "");
setGraphic(null);
}
}
}
@SuppressWarnings({ "rawtypes" })
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
if (!arg2) {
if (textField.getText().equals(""))
commit(0.0);
else {
double val = Double.parseDouble(textField.getText());
commit(val);
}
}
}
});
textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.ESCAPE) {
textField.setText("" + getItem());
cancelEdit();
event.consume();
}
// Navigate up and down in table
else if (event.getCode() == KeyCode.ENTER) {
TableView<S> table = getTableView();
int row = table.getEditingCell().getRow();
// Commit changes
if (textField.getText().equals(""))
commit(0.0);
else {
double val = Double.parseDouble(textField.getText());
commit(val);
}
// Do move
if (event.isShiftDown())
table.edit(row - 1, getTableColumn());
else {
table.edit(row + 1, getTableColumn());
}
}
// Move left and right in table
else if (event.getCode() == KeyCode.TAB) {
TableView<S> table = getTableView();
int row = table.getEditingCell().getRow();
// Save changes
if (textField.getText().equals(""))
commit(0.0);
else {
double val = Double.parseDouble(textField.getText());
commit(val);
}
ArrayList<TableColumn<S, ?>> cols = new ArrayList<TableColumn<S, ?>>();
int index = 0;
for (TableColumn<S, ?> c : table.getColumns()) {
if (c.isVisible() && c.isEditable())
cols.add(c);
if (c == getTableColumn())
index = cols.size() - 1;
}
// Do move
if (event.isShiftDown()) {
try {
TableColumn<S, ?> prevCol = cols.get(index - 1);
table.edit(row, prevCol);
} catch (Exception e) {
}
} else {
try {
TableColumn<S, ?> nextCol = cols.get(index + 1);
table.edit(row, nextCol);
} catch (Exception e) {
}
}
}
});
textField.setTextFormatter(new TextFormatter<String>((Change c) -> {
String text = c.getText();
TableView<S> table = getTableView();
if (table.getSelectionModel().getSelectedCells().size() == 0) {
return c;
}
TablePosition pasteCellPosition = table.getSelectionModel().getSelectedCells().get(0);
int clipRow = 0;
int clipCol = 0;
String curCellText = text;
if (text.contains("t") || text.contains("n")) {
StringTokenizer row = new StringTokenizer(text, "n");
boolean hasRun = false;
while (row.hasMoreTokens() || !hasRun) {
String r = row.nextToken();
StringTokenizer col;
if (r != null)
col = new StringTokenizer(r, "t");
else
col = new StringTokenizer(text, "t");
hasRun = true;
clipCol = 0;
while (col.hasMoreTokens()) {
String content = col.nextToken();
if (clipRow == 0 && clipCol == 0) {
curCellText = content;
}
// calculate the position in the table cell
int rowTable = pasteCellPosition.getRow() + clipRow;
int colTable = pasteCellPosition.getColumn() + clipCol;
// Skip hidden columns before current cell
for (int i = 0; i < colTable; i++)
if (!table.getColumns().get(i).isVisible())
colTable++;
// Skip hidden columns between current and goal
while (!table.getColumns().get(colTable).isVisible()) {
if (colTable >= table.getColumns().size())
break;
colTable++;
}
// Add row if we reach the end
if (rowTable >= table.getItems().size()) {
if (table.getItems().get(0) instanceof EditableTableRow)
((EditableTableRow) table.getItems().get(0)).addRowToTable(table);
// continue;
}
if (colTable >= table.getColumns().size()) {
continue;
}
try {
double val = Double.parseDouble(content);
commit(val, rowTable, colTable);
} catch (Exception e) {
try {
int val = Integer.parseInt(content);
commit(val, rowTable, colTable);
} catch (Exception e2) {
commit(content, rowTable, colTable);
}
}
clipCol++;
}
clipRow++;
}
}
c.setText(curCellText);
return c;
}));
textField.requestFocus();
textField.selectAll();
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
你不能遍历所有单元格;您无法知道已经创建了哪些单元格,它们代表实际的项,等等。
你可以调用
getTableView().edit(-1, null);
将具有取消编辑的效果。(见Javadocs。)实际上,调用
可能更好getTableView().edit(getIndex(), getTableColumn());
而不是调用startEdit()
。这将(应该)?我还没有测试…)为你调用startEdit()
。换句话说,
public EditingCell() {
addEventFilter(MouseEvent.MOUSE_CLICKED, e ->
getTableView().edit(getIndex(), getTableColumn()));
}
作为一个题外话,为什么你去所有的麻烦使单元格实现非常一般,但然后假设单元格值工厂是PropertyValueFactory
的一个实例?当然,你可以通过
ObservableValue<T> obs = getTableColumn().getCellObservableValue(getTableView().getItems().get(getIndex()));
,然后按
if (obs instanceof WritableValue) {
((WritableValue<?>) obs).setValue(val);
}