Проблема заключается в следующем:
У меня есть TableView
с ComboBoxes
, где для каждой TableCell я могу выбрать
значение из выпадающих списков. Проблема в том, что, если у меня много строк и столбцов, мне приходится много щелкать, чтобы выбрать подходящее значение в каждом поле со списком.
Чтобы выбрать значение в выпадающем списке, я должен щелкнуть четыре раза, чтобы выбрать значение. Один раз, чтобы выбрать ячейку, один раз, чтобы установить графику comboBox, снова, чтобы открыть всплывающее окно для комбинированного списка, где я могу выбрать значение и, наконец, выбрать значение.
Я хотел бы использовать doubleClick, чтобы я мог быстро открыть comboBox, а затем выбрать значение. Это сэкономит клик и много времени, если у меня будет много значений для выбора.
Я пытался ее решить, но ни одно из решений не работало правильно,
Я добавляю их сюда, может быть, вы можете увидеть, где я ошибся, и исправить это.
Я пробовал два аналогичных способа:
игнорируйте startEdit () и добавьте прослушиватель мыши в ячейку, а затем дважды щелкните comboBox.
Это имеет проблему, если я щелкаю по другой ячейке, предыдущая не устанавливает графику на ноль, даже если я поставлю setGrapichs(null)
в cancelEdit
и commitEdit
. Другая проблема заключается в том, что иногда значение не передается в модель.
Второй подход состоял в том, чтобы обработать его в startEdit (), поэтому просто вызовите .show()
там и .hide()
как при фиксации, так и при отмене редактирования, в зависимости от действия. Это дает мне NPE, если я обертываю TableView
в TitledPane
и после того, как я сверну / разверну его, я пытаюсь выбрать значение, после двойного щелчка он дает NPE:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.positionAndShowPopup(ComboBoxPopupControl.java:197)
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.show(ComboBoxPopupControl.java:170)
at com.sun.javafx.scene.control.skin.ComboBoxBaseSkin.handleControlPropertyChanged(ComboBoxBaseSkin.java:127)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.handleControlPropertyChanged(ComboBoxListViewSkin.java:159)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:72)
at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
at javafx.scene.control.ComboBoxBase.setShowing(ComboBoxBase.java:185)
at javafx.scene.control.ComboBoxBase.show(ComboBoxBase.java:391)
at stackoverflow.combo.ComboTableCell.startEdit(ComboTableCell.java:47)
at javafx.scene.control.TableCell.updateEditing(TableCell.java:556)
at javafx.scene.control.TableCell.lambda$new$26(TableCell.java:142)
at javafx.beans.WeakInvalidationListener.invalidated(WeakInvalidationListener.java:83)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.control.TableView.setEditingCell(TableView.java:1145)
at javafx.scene.control.TableView.edit(TableView.java:1459)
at com.sun.javafx.scene.control.behavior.TableCellBehavior.edit(TableCellBehavior.java:108)
at com.sun.javafx.scene.control.behavior.TableCellBehavior.edit(TableCellBehavior.java:38)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.handleClicks(CellBehaviorBase.java:271)
at com.sun.javafx.scene.control.behavior.TableCellBehaviorBase.simpleSelect(TableCellBehaviorBase.java:218)
at com.sun.javafx.scene.control.behavior.TableCellBehaviorBase.doSelect(TableCellBehaviorBase.java:148)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mouseReleased(CellBehaviorBase.java:159)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
Вот код, который вы можете проверить:
TableCell:
public class ComboTableCell<T,S> extends TableCell<T,S> {
private ComboBox<S> combo;
public ComboTableCell(Collection<S> items) {
combo = new ComboBox<>();
combo.setItems(FXCollections.observableArrayList(items));
combo.prefWidthProperty().bind(widthProperty());
combo.valueProperty().addListener((observable, oldValue, newValue) -> commitEdit(newValue));
// 1. Solution with mouse event
// this.setOnMouseClicked(event -> {
// if(event.getClickCount() == 2){
// combo.getSelectionModel().select(getItem());
// setText(null);
// setGraphic(combo);
// if(!combo.isShowing()){
// combo.show();
// }
// }
// });
}
// 2. Solution with startEdit
@Override
public void startEdit() {
combo.getSelectionModel().select(getItem());
super.startEdit();
setText(null);
setGraphic(combo);
if(!combo.isShowing()){
combo.show();
}
}
@Override
protected void updateItem(S item, boolean empty) {
super.updateItem(item, empty);
if(empty){
setText(null);
setGraphic(null);
return;
}
setText(getItem().toString());
setGraphic(null);
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setGraphic(null);
if(combo.isShowing()){
combo.hide();
}
}
@Override
public void commitEdit(S newValue) {
super.commitEdit(newValue);
setGraphic(null);
setText(getItem().toString());
if(combo.isShowing()){
combo.hide();
}
setGraphic(null);
setText(getItem().toString());
}
}
Контроллер:
public class Controller implements Initializable {
@FXML
private TableView<Model> table;
@FXML
private TableColumn<Model,String> col;
@Override
public void initialize(URL location, ResourceBundle resources) {
table.setEditable(true);
col.setCellValueFactory(data -> data.getValue().text);
col.setCellFactory(factory -> new ComboTableCell<>(Arrays.asList("a","b","c")));
table.setItems(FXCollections.observableArrayList(Arrays.asList(new Model("a"),new Model("b"))));
}
static class Model{
private StringProperty text;
public Model(String text) {
this.text = new SimpleStringProperty(text);
}
public String getText() {
return text.get();
}
public StringProperty textProperty() {
return text;
}
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TitledPane?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="stackoverflow.combo.Controller">
<TitledPane text="Table">
<TableView fx:id="table">
<columns>
<TableColumn fx:id="col" prefWidth="200"/>
</columns>
</TableView>
</TitledPane>
</AnchorPane>
Я бы предпочел любое решение, которое дает мне ожидаемый результат, вы можете предложить мне даже другое решение, которое использует меньше обходных путей или исправление для одного из предложенных мной "решений".
JDK версия 1.8.0_121