问题如下:
我有一个TableView
with ComboBoxes
对于每个 TableCell 我可以选择
组合框中的值。问题是,如果我有很多行和列,我必须多次单击才能在每个组合框中选择适当的值。
要在组合框中选择一个值,我必须单击四次才能选择该值。一旦选择单元格,一次设置组合框的图形,再次打开组合框的弹出窗口,我可以在其中选择值,最后选择值。
我想使用 doubleClick,这样我可以快速打开组合框,然后选择值。如果我有很多值需要选择,这将节省点击次数和大量时间。
我尝试解决它,但没有一个解决方案能正常工作,
我把它们加在这里,也许你可以看到我哪里错了并改正。
我尝试了两种类似的方法:
忽略 startEdit() 并向单元格添加鼠标单击侦听器,然后双击弹出组合框。
如果我单击另一个单元格,就会出现问题,前一个单元格不会将图形设置为空,即使我将setGrapichs(null)
同时在cancelEdit
and commitEdit
。另一个问题是有时不会将值提交给模型。
-
第二种方法是在 startEdit() 中处理它,因此只需调用.show()
那里和.hide()
它在提交和取消编辑中,具体取决于操作。这给了我一个 NPE,如果我把TableView
in a 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)
这是您可以检查的代码:
表格单元格:
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