问题
I have an event listener that listens for keyboard events. When i try to enter edit mode by using key event, for some strange reason an incorrect cell enters edit mode.
For example I want to edit a cell. I use keyboard arrows to go to the cell I want to edit i.e. the cell that is focused. By clicking a letter on the keyboard, the focused cell should enter edit mode. When I try to edit the focused cell, the wrong cell enters edit mode.
private final class EditCell extends TableCell<SimpleStringProperty, String> implements GenericTable
{
public EditCell()
{
// Add event listsner. table is a TableView
table.setOnKeyPressed(keyEvent -> this.handleKeyPressed(keyEvent));
}
public void handleKeyPressed(KeyEvent key)
{
// Keyboard events
if (key.getCode().isLetterKey())
{
if (!this.isEditing())
{
this.edit = true;
// focus index
int focusIndex = this.table.getSelectionModel().getFocusedIndex();
this.changeTableCellFocus(this.table, focusIndex);
this.startEdit();
}
}
}
// startEdit() function
@Override
public void startEdit()
{
if (this.edit)
{
LOGGER.info("Start editing on cell index: " + this.getIndex());
super.startEdit();
this.createTextField();
this.setText(null);
this.setGraphic(this.textField);
this.textField.selectAll();
this.textField.requestFocus();
this.textField.setOnKeyPressed(keyEvent -> this.handleKeyPressed(keyEvent));
this.textField.focusedProperty()
.addListener((observable, oldValue, newValue) -> this.onTextFieldFocusChange(observable,
oldValue,
newValue));
}
}
// Change focus
public void changeTableCellFocus(final TableView<?> table, final int focusIndex)
{
table.requestFocus();
table.getSelectionModel().clearAndSelect(focusIndex);
table.getFocusModel().focus(focusIndex);
}
}
Before entering edit mode, I change focus to the clicked cell and then call the startEdit() method. I have attempted to debug the issue but with no luck. I have noticed that the focusIndex is different from the current cell index. I'm not sure why the index is different.
回答1:
The problem with your code is that every cell is calling table.setOnKeyPressed(...) as it is created. This works like any other set method, so the keyPressed handler on the table is just set to the one from the last EditCell that was created. You have no control over actual creation of cells, and this is not necessarily (and unlikely) to be the cell that happens to be focused.
The TableView has enough API for you to be able to manage this directly from the table. In particular
table.getFocusModel().getFocusedCell()
will give you a TablePosition representing the currently focused cell. From that you can retrieve the corresponding row index and TableColumn. Then you just need to call table.edit(int row, TableColumn<...> column); to instruct the appropriate cell to go into editing mode.
Here's a complete example. I didn't make much effort to make the editing "pretty" in terms of selecting text etc in the text field, and you might want to implement edit cancel somehow, but this should get you started.
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TableViewEditOnType extends Application {
@Override
public void start(Stage primaryStage) {
TableView<List<StringProperty>> table = new TableView<>();
table.getSelectionModel().setCellSelectionEnabled(true);
table.setEditable(true);
for (int i = 0; i < 10; i++) {
table.getColumns().add(createColumn(i));
List<StringProperty> rowData = new ArrayList<>();
table.getItems().add(rowData);
for (int j = 0; j < 10 ; j++) {
rowData.add(new SimpleStringProperty(String.format("Cell [%d, %d]", i, j)));
}
}
table.setOnKeyTyped(event -> {
TablePosition<List<StringProperty>, String> focusedCell = table.getFocusModel().getFocusedCell();
if (focusedCell != null) {
table.getItems().get(focusedCell.getRow()).get(focusedCell.getColumn()).set(event.getCharacter());
table.edit(focusedCell.getRow(), focusedCell.getTableColumn());
}
});
Scene scene = new Scene(new BorderPane(table), 880, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableColumn<List<StringProperty>, String> createColumn(int colIndex) {
TableColumn<List<StringProperty>, String> col = new TableColumn<>("Column "+colIndex);
col.setCellValueFactory(cellData -> cellData.getValue().get(colIndex));
col.setCellFactory(column -> new EditCell());
return col ;
}
private static class EditCell extends TableCell<List<StringProperty>, String> {
private final TextField textField = new TextField();
EditCell() {
textProperty().bind(itemProperty());
setGraphic(textField);
setContentDisplay(ContentDisplay.TEXT_ONLY);
textField.setOnAction(evt -> commitEdit(textField.getText()));
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (! isNowFocused) {
commitEdit(textField.getText());
}
});
}
@Override
public void startEdit() {
super.startEdit();
textField.setText(getItem());
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.requestFocus();
}
@Override
public void cancelEdit() {
super.cancelEdit();
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
@Override
public void commitEdit(String text) {
super.commitEdit(text);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
public static void main(String[] args) {
launch(args);
}
}
来源:https://stackoverflow.com/questions/28456215/tableview-edit-focused-cell