具有可编辑 ListView 的 ListCell 作为图形:commitEdit 上的 ClassCastException
ListCell with editable ListView as graphic: ClassCastException on commitEdit
在 JavaFx v17、JDK v17、Maven、IntelliJ 中:
Listview (=TOKListView) 在 Listview (=SIGListView) 的每一行中。当我编辑 TOKListView 的单元格时,我在 startEdit() 部分调用了 commitEdit(),然后我收到错误 class TokenWord cannot be cast to class Signification
。 SIGListView 不应该,但会执行 updateItem(),但为什么呢?
Main.class // ReprEx
public class Main extends Application {
public static void main(String[] args) {
Application.launch(Main.class);
}
public class Signification {
ArrayList<TokenWord> tokenWords;
public Signification(ArrayList<TokenWord> tokenWords) {
this.tokenWords = tokenWords;
}
public ArrayList<TokenWord> getTokenWords() {
return tokenWords;
}
}
public class TokenWord {
String Text;
public TokenWord(String text) {
Text = text;
}
public String getText() {
return Text;
}
}
final ListView<Signification> significationListView = new ListView<>();
final ArrayList<Signification> significations = new ArrayList<>();
@Override
public void start(Stage stage) {
significations.add(
new Signification(new ArrayList<TokenWord>(Arrays.asList(
new TokenWord("One")
))));
significationListView.setCellFactory(significationListView -> {
ListCell<Signification> siCell = new ListCell<Signification>() {
//PROBLEM AREA ---- START --------------------------------------
//########## PROBLEM CONSUMED (of PROBLEM FIRED see below) #########
@Override
public void updateItem(Signification sigItem, boolean empty) {
super.updateItem(sigItem, empty);
if ((!empty) && (sigItem != null)) {
ListView<TokenWord> tokenWordListView = new ListView<TokenWord>();
tokenWordListView.setEditable(true);
tokenWordListView.setOrientation(Orientation.HORIZONTAL);
tokenWordListView.setCellFactory(twListView -> {
// each Cell a new Listview
ListCell<TokenWord> twCell = new ListCell<TokenWord>() {
@Override
public void updateItem(TokenWord twItem, boolean empty) {
super.updateItem(twItem, empty);
if ((!empty) && (twItem != null)) setText(twItem.getText());
}
@Override
public void startEdit() {
if (!isEditable() || !getListView().isEditable()) return;
super.startEdit();
if (isEditing()) {
setText("");
TextField textField = new TextField(getItem().getText());
textField.setOnAction(actionEvent -> {
//########## PROBLEM FIRED ###########
commitEdit(new TokenWord(textField.getText()));
});
setGraphic(textField);
} else setGraphic(null);
}
};
return twCell;
});
tokenWordListView.getItems().addAll(sigItem.getTokenWords());
setGraphic(tokenWordListView);
} else {
setGraphic(null);
}
}
//PROBLEM AREA ---- END --------------------------------------
};
siCell.setPrefHeight(40);
return siCell;
});
significationListView.getItems().addAll(significations);
stage.setScene(new Scene(new StackPane(significationListView), 400, 150));
stage.show();
}
}
错误信息:
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class org.example.TheApp$TokenWord cannot be cast to class org.example.TheApp$Signification (org.example.TheApp$TokenWord and org.example.TheApp$Signification are in unnamed module of loader 'app')
at org.example.TheApp.updateItem(TheApp.java:61)
at javafx.scene.control.ListCell.updateItem(ListCell.java:481)
at javafx.scene.control.ListCell.lambda$new(ListCell.java:168)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:239)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:211)
at javafx.collections.ModifiableObservableListBase.set(ModifiableObservableListBase.java:170)
at javafx.scene.control.ListView.lambda$new(ListView.java:375)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
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.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8792)
at javafx.scene.control.ListCell.commitEdit(ListCell.java:390)
at org.example.TheApp.lambda$startEdit[=11=](TheApp.java:94)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
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.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:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8792)
at com.sun.javafx.scene.control.behavior.TextFieldBehavior.fire(TextFieldBehavior.java:154)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.lambda$keyMapping(TextInputControlBehavior.java:332)
at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
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.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$KeyHandler.process(Scene.java:4105)
at javafx.scene.Scene.processKeyEvent(Scene.java:2156)
at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2630)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:218)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:150)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent(GlassViewEventHandler.java:250)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:249)
at com.sun.glass.ui.View.handleKeyEvent(View.java:548)
at com.sun.glass.ui.View.notifyKey(View.java:972)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class org.example.TheApp$TokenWord cannot be cast to class org.example.TheApp$Signification (org.example.TheApp$TokenWord and org.example.TheApp$Signification are in unnamed module of loader 'app')
at org.example.TheApp.updateItem(TheApp.java:61)
at javafx.scene.control.ListCell.updateItem(ListCell.java:481)
at javafx.scene.control.ListCell.indexChanged(ListCell.java:337)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:120)
at javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1807)
at javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:2191)
at javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1327)
at javafx.scene.Parent.layout(Parent.java:1207)
at javafx.scene.Parent.layout(Parent.java:1214)
at javafx.scene.Parent.layout(Parent.java:1214)
at javafx.scene.Scene.doLayoutPass(Scene.java:579)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2515)
at com.sun.javafx.tk.Toolkit.lambda$runPulse(Toolkit.java:421)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:420)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:450)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit(QuantumToolkit.java:353)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run$$$capture(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
发生错误是因为编辑是通过事件控制的,我们有一个 ListView,其中的单元格包含一个 ListView:
- 提交沿着通常的事件调度链传送
- 提交从编辑单元格(包含文本字段的单元格)触发到内部 listView
- 内部 listView 的默认提交处理程序通过保存编辑的值来处理事件
- 然后它冒泡到外部 listView 的提交处理程序,在那里它导致 class 转换异常
最后一个发生是因为默认提交处理程序不使用该事件。解决办法就是吃掉它。
一些代码(为清晰起见,提取到单独的 class,也可以内联完成)
public class OuterCell extends ListCell<Signification> {
ListView<TokenWord> tokenWordListView;
{
tokenWordListView = new ListView<TokenWord>();
tokenWordListView.setEditable(true);
tokenWordListView.setOrientation(Orientation.HORIZONTAL);
// grab default commit handler
EventHandler<EditEvent<TokenWord>> handler = tokenWordListView.getOnEditCommit();
tokenWordListView.setOnEditCommit(t -> {
// let default handler save the edited value
handler.handle(t);
// consume to prevent dispatching the event to the outer list
t.consume();
});
// use TextFieldListCell for inner cell
StringConverter<TokenWord> converter = new StringConverter<>() {
@Override
public String toString(TokenWord token) {
return token != null ? token.getText() : "";
}
@Override
public TokenWord fromString(String string) {
return new TokenWord(string);
}
};
tokenWordListView.setCellFactory(TextFieldListCell.forListView(converter));
setPrefHeight(40);
}
@Override
public void updateItem(Signification sigItem, boolean empty) {
super.updateItem(sigItem, empty);
if ((!empty) && (sigItem != null)) {
tokenWordListView.getItems().setAll(sigItem.getTokenWords());
setGraphic(tokenWordListView);
} else {
setGraphic(null);
}
}
}
在 JavaFx v17、JDK v17、Maven、IntelliJ 中:
Listviewclass TokenWord cannot be cast to class Signification
。 SIGListView 不应该,但会执行 updateItem(),但为什么呢?
Main.class // ReprEx
public class Main extends Application {
public static void main(String[] args) {
Application.launch(Main.class);
}
public class Signification {
ArrayList<TokenWord> tokenWords;
public Signification(ArrayList<TokenWord> tokenWords) {
this.tokenWords = tokenWords;
}
public ArrayList<TokenWord> getTokenWords() {
return tokenWords;
}
}
public class TokenWord {
String Text;
public TokenWord(String text) {
Text = text;
}
public String getText() {
return Text;
}
}
final ListView<Signification> significationListView = new ListView<>();
final ArrayList<Signification> significations = new ArrayList<>();
@Override
public void start(Stage stage) {
significations.add(
new Signification(new ArrayList<TokenWord>(Arrays.asList(
new TokenWord("One")
))));
significationListView.setCellFactory(significationListView -> {
ListCell<Signification> siCell = new ListCell<Signification>() {
//PROBLEM AREA ---- START --------------------------------------
//########## PROBLEM CONSUMED (of PROBLEM FIRED see below) #########
@Override
public void updateItem(Signification sigItem, boolean empty) {
super.updateItem(sigItem, empty);
if ((!empty) && (sigItem != null)) {
ListView<TokenWord> tokenWordListView = new ListView<TokenWord>();
tokenWordListView.setEditable(true);
tokenWordListView.setOrientation(Orientation.HORIZONTAL);
tokenWordListView.setCellFactory(twListView -> {
// each Cell a new Listview
ListCell<TokenWord> twCell = new ListCell<TokenWord>() {
@Override
public void updateItem(TokenWord twItem, boolean empty) {
super.updateItem(twItem, empty);
if ((!empty) && (twItem != null)) setText(twItem.getText());
}
@Override
public void startEdit() {
if (!isEditable() || !getListView().isEditable()) return;
super.startEdit();
if (isEditing()) {
setText("");
TextField textField = new TextField(getItem().getText());
textField.setOnAction(actionEvent -> {
//########## PROBLEM FIRED ###########
commitEdit(new TokenWord(textField.getText()));
});
setGraphic(textField);
} else setGraphic(null);
}
};
return twCell;
});
tokenWordListView.getItems().addAll(sigItem.getTokenWords());
setGraphic(tokenWordListView);
} else {
setGraphic(null);
}
}
//PROBLEM AREA ---- END --------------------------------------
};
siCell.setPrefHeight(40);
return siCell;
});
significationListView.getItems().addAll(significations);
stage.setScene(new Scene(new StackPane(significationListView), 400, 150));
stage.show();
}
}
错误信息:
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class org.example.TheApp$TokenWord cannot be cast to class org.example.TheApp$Signification (org.example.TheApp$TokenWord and org.example.TheApp$Signification are in unnamed module of loader 'app')
at org.example.TheApp.updateItem(TheApp.java:61)
at javafx.scene.control.ListCell.updateItem(ListCell.java:481)
at javafx.scene.control.ListCell.lambda$new(ListCell.java:168)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:239)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:211)
at javafx.collections.ModifiableObservableListBase.set(ModifiableObservableListBase.java:170)
at javafx.scene.control.ListView.lambda$new(ListView.java:375)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
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.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8792)
at javafx.scene.control.ListCell.commitEdit(ListCell.java:390)
at org.example.TheApp.lambda$startEdit[=11=](TheApp.java:94)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
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.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:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8792)
at com.sun.javafx.scene.control.behavior.TextFieldBehavior.fire(TextFieldBehavior.java:154)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.lambda$keyMapping(TextInputControlBehavior.java:332)
at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
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.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$KeyHandler.process(Scene.java:4105)
at javafx.scene.Scene.processKeyEvent(Scene.java:2156)
at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2630)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:218)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:150)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent(GlassViewEventHandler.java:250)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:249)
at com.sun.glass.ui.View.handleKeyEvent(View.java:548)
at com.sun.glass.ui.View.notifyKey(View.java:972)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class org.example.TheApp$TokenWord cannot be cast to class org.example.TheApp$Signification (org.example.TheApp$TokenWord and org.example.TheApp$Signification are in unnamed module of loader 'app')
at org.example.TheApp.updateItem(TheApp.java:61)
at javafx.scene.control.ListCell.updateItem(ListCell.java:481)
at javafx.scene.control.ListCell.indexChanged(ListCell.java:337)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:120)
at javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1807)
at javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:2191)
at javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1327)
at javafx.scene.Parent.layout(Parent.java:1207)
at javafx.scene.Parent.layout(Parent.java:1214)
at javafx.scene.Parent.layout(Parent.java:1214)
at javafx.scene.Scene.doLayoutPass(Scene.java:579)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2515)
at com.sun.javafx.tk.Toolkit.lambda$runPulse(Toolkit.java:421)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:420)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:450)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit(QuantumToolkit.java:353)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run$$$capture(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
发生错误是因为编辑是通过事件控制的,我们有一个 ListView,其中的单元格包含一个 ListView:
- 提交沿着通常的事件调度链传送
- 提交从编辑单元格(包含文本字段的单元格)触发到内部 listView
- 内部 listView 的默认提交处理程序通过保存编辑的值来处理事件
- 然后它冒泡到外部 listView 的提交处理程序,在那里它导致 class 转换异常
最后一个发生是因为默认提交处理程序不使用该事件。解决办法就是吃掉它。
一些代码(为清晰起见,提取到单独的 class,也可以内联完成)
public class OuterCell extends ListCell<Signification> {
ListView<TokenWord> tokenWordListView;
{
tokenWordListView = new ListView<TokenWord>();
tokenWordListView.setEditable(true);
tokenWordListView.setOrientation(Orientation.HORIZONTAL);
// grab default commit handler
EventHandler<EditEvent<TokenWord>> handler = tokenWordListView.getOnEditCommit();
tokenWordListView.setOnEditCommit(t -> {
// let default handler save the edited value
handler.handle(t);
// consume to prevent dispatching the event to the outer list
t.consume();
});
// use TextFieldListCell for inner cell
StringConverter<TokenWord> converter = new StringConverter<>() {
@Override
public String toString(TokenWord token) {
return token != null ? token.getText() : "";
}
@Override
public TokenWord fromString(String string) {
return new TokenWord(string);
}
};
tokenWordListView.setCellFactory(TextFieldListCell.forListView(converter));
setPrefHeight(40);
}
@Override
public void updateItem(Signification sigItem, boolean empty) {
super.updateItem(sigItem, empty);
if ((!empty) && (sigItem != null)) {
tokenWordListView.getItems().setAll(sigItem.getTokenWords());
setGraphic(tokenWordListView);
} else {
setGraphic(null);
}
}
}