以下問題:我需要知道在特定時刻,天氣我的TableView目前正在編輯或不編輯。我使用了editingCellProperty,並綁定了一個特定的業務邏輯,以便在表格切換這些模式時得到通知。如何正確避免beeing可編輯的特定TableViewCells?
不幸的是,狀態並不總是顯示正確,因爲我有特定的單元格(在同一列中),根本不應該被編輯,但仍然點擊不可編輯的單元格時,TablePosition被設置爲editingCellProperty,因此我得到了我的TableView正在編輯的信息,儘管它已經被告知,但是這個單元格是不可編輯的,編輯模式從未真正開始。
我創建了一個小例子,其中ColumnName的所有偶數行都是可編輯的,而奇數行不是。
例碼:
public class TableViewEditableStateError extends Application
{
public static void main(final String[] args)
{
launch(args);
}
@Override
public void start(final Stage primaryStage)
{
Item item1 = new Item(1, "Item1");
Item item2 = new Item(2, "Item2");
Item item3 = new Item(3, "Item3");
Item item4 = new Item(4, "Item4");
ObservableList<Item> itemList = FXCollections.observableArrayList(item1, item2, item3, item4);
TableColumn<Item, Integer> columnId = new TableColumn<>("ColumnId");
TableColumn<Item, String> columnName = new TableColumn<>("ColumnName");
columnId.setCellValueFactory(new PropertyValueFactory<Item, Integer>("id"));
columnName.setCellValueFactory(new PropertyValueFactory<Item, String>("name"));
// columnName.setCellFactory(TextFieldTableCell.forTableColumn()); -> Using own implementation for editablestate-behaviour
columnName.setCellFactory(new Callback<TableColumn<Item, String>, TableCell<Item, String>>()
{
@Override
public TableCell<Item, String> call(final TableColumn<Item, String> column)
{
TableCell<Item, String> cell = new EditableTableCell<Item>()
{
@Override
public void startEdit()//Business-Rule to deceide, which cell is editable.
{
if (getTableRow().getIndex() % 2 != 0/* Only Odd Values are editable. -> Any Random Condition */)
{
System.out.println("Do not initiate Editing.");
return;
}
System.out.println("initiate Editing.");
super.startEdit();
}
};
return cell;
}
});
columnName.setOnEditCommit(new EventHandler<CellEditEvent<Item, String>>()
{
@Override
public void handle(final CellEditEvent<Item, String> event)
{
final Item item = event.getRowValue();
System.out.println("Change Item " + item + " from " + event.getOldValue() + " to new value "
+ event.getNewValue());
item.setName(event.getNewValue());
}
});
final TableView<Item> tableView = new TableView<>(itemList);
tableView.getColumns().add(columnId);
tableView.getColumns().add(columnName);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableView.setEditable(true);
columnId.setEditable(false);
Label label = new Label("Editing-State: is not editing...");
//Listener to record editing behaviour:
tableView.editingCellProperty().addListener(new ChangeListener<TablePosition<Item, ?>>()
{
@Override
public void changed(final ObservableValue<? extends TablePosition<Item, ?>> observable,
final TablePosition<Item, ?> oldValue, final TablePosition<Item, ?> newValue)
{
System.out.println("Editstate changed to: " + newValue);
if (newValue != null)
label.setText("Editing-State: is editing...");
else
label.setText("Editing-State: is not editing...");
}
});
BorderPane layout = new BorderPane();
layout.setCenter(tableView);
layout.setTop(label);
Scene scene = new Scene(layout, 400, 400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
class EditableTableCell<S> extends TableCell<S, String>
{
protected TextField textField;
@Override
public void startEdit()
{
super.startEdit();
if (textField == null)
{
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable()
{
@Override
public void run()
{
textField.selectAll();
textField.requestFocus();
}
});
}
@Override
public void cancelEdit()
{
super.cancelEdit();
setText(getItem() == null ? "" : getItem().toString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
textField = null;
}
@Override
public void updateItem(final String item, final boolean empty)
{
super.updateItem(item, empty);
if (empty)
{
setText(null);
setGraphic(null);
}
else
{
if (isEditing())
{
if (textField != null)
{
textField.setText(getItem() == null ? "" : getItem().toString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
else
{
setText(getItem() == null ? "" : getItem().toString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField()
{
textField = new TextField(getItem() == null ? "" : getItem().toString());
textField.setOnKeyPressed(new EventHandler<KeyEvent>()
{
@Override
public void handle(final KeyEvent keyEvent)
{
if (keyEvent.getCode() == KeyCode.ENTER)
{
commitEdit(textField.getText());
}
else if (keyEvent.getCode() == KeyCode.ESCAPE)
{
cancelEdit();
}
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>()
{
@Override
public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue,
final Boolean newValue)
{
if (!newValue && textField != null)
{
final String text = textField.getText();
commitEdit(text);
}
}
});
}
}
}
數據類項目:
public class Item
{
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty name = new SimpleStringProperty();
public Item(final int id, final String name)
{
this.id.set(id);
this.name.set(name);
}
public int getId()
{
return id.get();
}
public String getName()
{
return name.get();
}
public void setId(final int id)
{
this.id.set(id);
}
public void setName(final String name)
{
this.name.set(name);
}
public IntegerProperty idProperty()
{
return id;
}
public StringProperty nameProperty()
{
return name;
}
}
我縮小我的問題到TableView中的editCell方法,因爲它不反應的細胞特定的可修改狀態:
/**
* Causes the cell at the given row/column view indexes to switch into
* its editing state, if it is not already in it, and assuming that the
* TableView and column are also editable.
*/
public void edit(int row, TableColumn<S,?> column) {
if (!isEditable() || (column != null && ! column.isEditable())) {
return;
}
if (row < 0 && column == null) {
setEditingCell(null);
} else {
setEditingCell(new TablePosition<>(this, row, column));
}
}
但是由於setEditingCell()是一個私有方法,我無法按照我希望的方式重寫edit-Method。所以我很好奇:任何人都可以告訴我在同一列中實現動態可編輯表格單元格的正確方法,而TableView的editingCell-State將始終保持正確嗎?
我想你可以按照你的邏輯在變化監聽器。我做了類似於你的事來阻止編輯,但我不需要聽。如果需要,您可以從TablePosition訪問該項目。 – brian
這就是我想要做的,但唯一的問題是,即使當我單擊不可編輯的單元格時,也會使用相應的表格位置(而不是null)調用changelistener方法,因爲TableViews編輯方法不會了解列中的非可編輯單元格(在我的示例中,每隔一行)。你檢查過財產,而在你的情況下阻止編輯?我很好奇你如何實現阻塞方面,而不讓編輯方法改變屬性。 – crusam
看起來你在這個例子中沒有使用你的EditableCell類,但這是我檢查的地方。 '@Override public void startEdit(){if(!MyCondition)return; ''。但是,我添加了您的監聽器,並且它仍然會觸發。 – brian