考虑以下应用:
我希望每次单击按钮时,都会LineChart删除第一个数据。点击后的输出必须如下:
第一次点击后
第二次点击后
第三次点击后
但是,第一次点击后,我得到以下信息ClassCastException:
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
at javafx.controls@18/javafx.scene.chart.LineChart.createDataRemoveTimeline(LineChart.java:503)
at javafx.controls@18/javafx.scene.chart.LineChart.dataItemRemoved(LineChart.java:359)
at javafx.controls@18/javafx.scene.chart.XYChart.dataItemsChanged(XYChart.java:505)
at javafx.controls@18/javafx.scene.chart.XYChart$Series$1.onChanged(XYChart.java:1474)
at javafx.base@18/com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at javafx.base@18/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.base@18/javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:239)
at javafx.base@18/javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.base@18/javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.base@18/javafx.collections.ObservableListBase.endChange(ObservableListBase.java:211)
at javafx.base@18/javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:190)
at com.example.demo/com.example.demo.MyApplication.lambda$start$0(MyApplication.java:21)
at javafx.base@18/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base@18/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at javafx.base@18/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base@18/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base@18/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base@18/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@18/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@18/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@18/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@18/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@18/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base@18/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base@18/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics@18/javafx.scene.Node.fireEvent(Node.java:8797)
at javafx.controls@18/javafx.scene.control.Button.fire(Button.java:203)
at javafx.controls@18/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:208)
at javafx.controls@18/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at javafx.base@18/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
at javafx.base@18/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base@18/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at javafx.base@18/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base@18/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base@18/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base@18/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@18/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@18/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@18/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@18/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@18/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base@18/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base@18/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics@18/javafx.scene.Scene$MouseHandler.process(Scene.java:3881)
at javafx.graphics@18/javafx.scene.Scene.processMouseEvent(Scene.java:1874)
at javafx.graphics@18/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2607)
at javafx.graphics@18/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
at javafx.graphics@18/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics@18/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
at javafx.graphics@18/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at javafx.graphics@18/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
at javafx.graphics@18/com.sun.glass.ui.View.handleMouseEvent(View.java:551)
at javafx.graphics@18/com.sun.glass.ui.View.notifyMouse(View.java:937)
at javafx.graphics@18/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics@18/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
Run Code Online (Sandbox Code Playgroud)
代码如下:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class MyApplication extends Application {
@Override
public void start(Stage stage) {
LineChart<String,String> lineChart=createLineChart();
Button button = new Button("BUTTON");
button.setOnAction(event -> lineChart.getData().get(0).getData().remove(0));
VBox vBox=new VBox(button,lineChart);
Scene scene = new Scene(vBox);
stage.setScene(scene);
stage.show();
}
LineChart<String,String> createLineChart(){
LineChart<String, String> lineChart = new LineChart<>(new CategoryAxis(), new CategoryAxis());
lineChart.getData().add(new XYChart.Series<>());
for (int i = 0; i < 3; i++) {
lineChart.getData().get(0).getData().add(new XYChart.Data<>("X string %d".formatted(i+1), "Y string %d".formatted(i+1)));
}
lineChart.getXAxis().setTickLabelFont(new Font(20));
lineChart.getYAxis().setTickLabelFont(new Font(20));
return lineChart;
}
public static void main(String[] args) {
launch();
}
}
Run Code Online (Sandbox Code Playgroud)
问题
当我没有类型数据时,为什么会在toClassCastException转换时引发?StringNumberNumber
这是实现中的一个错误LineChart。我在https://bugs.openjdk.org/secure/Dashboard.jspa找不到它的有效错误报告。
问题出现在对方法的调用中createDataRemoveTimeline(...)(在当前实现中找到),该方法的实现如下:
private Timeline createDataRemoveTimeline(final Data<X,Y> item, final Node symbol, final Series<X,Y> series) {
Timeline t = new Timeline();
// save data values in case the same data item gets added immediately.
XYValueMap.put(item, ((Number)item.getYValue()).doubleValue());
t.getKeyFrames().addAll(new KeyFrame(Duration.ZERO, new KeyValue(item.currentYProperty(),
item.getCurrentY()), new KeyValue(item.currentXProperty(),
item.getCurrentX())),
new KeyFrame(Duration.millis(500), actionEvent -> {
if (symbol != null) getPlotChildren().remove(symbol);
removeDataItemFromDisplay(series, item);
XYValueMap.clear();
},
new KeyValue(item.currentYProperty(),
item.getYValue(), Interpolator.EASE_BOTH),
new KeyValue(item.currentXProperty(),
item.getXValue(), Interpolator.EASE_BOTH))
);
return t;
}
Run Code Online (Sandbox Code Playgroud)
该实现会缓存被删除的值(据我所知,这是需要的,以防在删除动画正在进行时添加回相同的值)Map<Data<X,Y>, Double>。这假设 y 值是 a Number(请注意方法第二行中的转换),这当然不一定正确。我认为这应该用 a 来实现Map<Data<X,Y>, Y>,尽管我还没有完全分析代码。
该createDataRemoveTimeline(...)方法从方法中调用dataItemRemoved(...)(当从数据系列之一中删除项目时调用),但仅当animated设置为 true 时。因此,一种解决方法是关闭动画:
lineChart.setAnimated(false);
Run Code Online (Sandbox Code Playgroud)