1 回答
TA贡献1868条经验 获得超4个赞
您可以子类化ComboBoxTableCell以添加您想要的行为。这是一个概念验证:
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.util.StringConverter;
public class AutoShowComboBoxTableCell<S, T> extends ComboBoxTableCell<S, T> {
/*
* May want to provide alternate constructors and static methods similar to
* the ComboBoxTableCell class (i.e. the superclass).
*/
private boolean enterPressed;
public AutoShowComboBoxTableCell(StringConverter<T> converter, ObservableList<T> values) {
super(converter, values);
getStyleClass().add("auto-show-combo-box-table-cell");
// Assumes TableView property is set only once (valid assumption?)
tableViewProperty().addListener(new InvalidationListener() {
@Override
public void invalidated(Observable observable) {
// Need to know if editing was started by the user pressing
// the ENTER key (see #startEdit())
EventHandler<KeyEvent> filter = event -> {
if (event.getCode() == KeyCode.ENTER) {
enterPressed = event.getEventType() == KeyEvent.KEY_PRESSED;
}
};
// Possible memory leak? Consider using WeakEventHandler (read docs)
getTableView().addEventFilter(KeyEvent.KEY_PRESSED, filter);
getTableView().addEventFilter(KeyEvent.KEY_RELEASED, filter);
observable.removeListener(this);
}
});
}
@Override
public void startEdit() {
if (isEditing()) return;
super.startEdit();
if (isEditing()) {
if (enterPressed) {
// Cell was put into edit mode by the user pressing ENTER. This causes
// problems since *releasing* ENTER while the ComboBox has the focus
// results in the value being committed; this leads to the current value
// being committed *immediately* after entering edit mode—not what we want.
// To fix that we consume the first ENTER-released event and then let all
// subsequent events through (by removing the event filter).
addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler<>() {
@Override public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
event.consume();
removeEventFilter(KeyEvent.KEY_RELEASED, this);
}
}
});
}
ComboBox<?> comboBox = (ComboBox<?>) getGraphic();
comboBox.requestFocus(); // Needed to allow releasing ENTER to commit the value
comboBox.show();
}
}
@Override
public void cancelEdit() {
if (isEditing()) {
super.cancelEdit();
requestTableViewFocus();
}
}
@Override
public void commitEdit(T newValue) {
if (isEditing()) {
super.commitEdit(newValue);
requestTableViewFocus();
}
}
// Allows user to keep navigating the table via the keyboard
private void requestTableViewFocus() {
TableView<S> tableView = getTableView();
if (tableView != null) {
tableView.requestFocus();
}
}
}
注意:以上使用了实现细节的知识,图形设置为编辑开始时的事实ComboBox以及导致提交编辑的原因。实施细节可能会更改,恕不另行通知。
添加回答
举报