I followed Example 13-11 Alternative Solution Of Cell Editing from the offical tableview tutorial, but I want my tableview
to act like a jtable
. This means that when a cell gets focus, it is ready to be edited, and using the arrow keys or the Enter key should instantly commit the edit and move to the next cell.
This is what I've gone so far:
First, I added
table.getSelectionModel().setCellSelectionEnabled(true);
Then I tried to modify the class EditingCell
:
class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
@Override
public void updateSelected(boolean selected) {
super.updateSelected(selected);
if (selected) {
createTextField();
setText(null);
setGraphic(textField);
textField.requestFocus();
textField.selectAll();
} else {
String value = textField.getText();
if (value != null) {
commitEdit(value);
} else {
commitEdit(null);
}
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
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) {
commitEdit(textField.getText());
}
}
});
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
if ((t.getCode() == KeyCode.ENTER) || (t.getCode() == KeyCode.UP) || (t.getCode() == KeyCode.DOWN) || (t.getCode() == KeyCode.LEFT) || (t.getCode() == KeyCode.RIGHT)) {
t.consume();
String value = textField.getText();
if (value != null) {
commitEdit(value);
} else {
commitEdit(null);
}
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
The tableview
I got is a mess - I have to click Enter key twice to end editing, and it won't commit the edit but instead cancels it.
Can anyone point me in the right direction?
Sadly that tutorial is missing some code fixes that were introduced later in the TextFieldTableCell class for the ENTER to work properly (RT-34685 - Use onAction instead of onKeyPressed and RT-28132 - Call requestFocus()).
Here is a working example, it's a reduced version of the TextFieldTableCell code which also uses Node.fireEvent() to move to the next cell after the commit (mimics a KeyPressed event):
class EditingCell extends TableCell<Person, String>
{
private TextField textField;
public EditingCell()
{
}
@Override
public void startEdit()
{
if (!isEditable() || !getTableView().isEditable()
|| !getTableColumn().isEditable())
{
return;
}
super.startEdit();
if (isEditing())
{
if (textField == null)
{
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
// requesting focus so that key input can immediately go into
// the TextField (see RT-28132)
textField.requestFocus();
}
}
@Override
public void cancelEdit()
{
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (empty)
{
setText(null);
setGraphic(null);
} else
{
if (isEditing())
{
if (textField != null)
{
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else
{
setText(getString());
setGraphic(null);
}
}
}
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)
{
commitEdit(textField.getText());
}
}
});
// Use onAction here rather than onKeyReleased (with check for
// Enter), as otherwise we encounter RT-34685
textField.setOnAction(t -> {
commitEdit(textField.getText());
t.consume();
});
textField.setOnKeyReleased(t -> {
if (t.getCode() == KeyCode.ESCAPE)
{
cancelEdit();
t.consume();
}
});
textField.setOnKeyPressed(new EventHandler<KeyEvent>()
{
@Override
public void handle(KeyEvent t)
{
if ((t.getCode() == KeyCode.UP) || (t.getCode() == KeyCode.DOWN)
|| (t.getCode() == KeyCode.LEFT)
|| (t.getCode() == KeyCode.RIGHT))
{
// Commit the current text
commitEdit(textField.getText());
// Let's move out simulating a key press in this Cell
KeyEvent event = new KeyEvent(t.getSource(), t.getTarget(),
KeyEvent.KEY_PRESSED, "", "", t.getCode(), false, false,
false, false);
EditingCell.this.fireEvent(event);
}
}
});
}
private String getString()
{
return getItem() == null ? "" : getItem().toString();
}
}
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With