Charts 定期修改JavaFX StackedBarChart类别
我试图找到一种方法来更新JavaFX CategoryAxis()的类别。我制作了一个可观察的类别列表,它们也会在plot()函数中进行更新。但是,如果我尝试向该系列添加一个新项,则会得到一个java.lang.IllegalStateException。虽然我知道,不是一个状态导致了错误,而且动态添加似乎是问题所在。下面我附上了我的代码Charts 定期修改JavaFX StackedBarChart类别,charts,javafx,Charts,Javafx,我试图找到一种方法来更新JavaFX CategoryAxis()的类别。我制作了一个可观察的类别列表,它们也会在plot()函数中进行更新。但是,如果我尝试向该系列添加一个新项,则会得到一个java.lang.IllegalStateException。虽然我知道,不是一个状态导致了错误,而且动态添加似乎是问题所在。下面我附上了我的代码 package application; import java.text.SimpleDateFormat; import java.util.Arra
package application;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
final XYChart.Series series1 = new XYChart.Series();
final XYChart.Series series2 = new XYChart.Series();
ObservableList<XYChart.Data> xyList1 = FXCollections.observableArrayList();
ObservableList<XYChart.Data> xyList2 = FXCollections.observableArrayList();
ObservableList<String> myXaxis = FXCollections.observableArrayList();
int i;
@Override public void start(Stage stage) {
stage.setTitle("Line Chart Sample");
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Month");
final StackedBarChart<String,Number> lineChart =
new StackedBarChart<String,Number>(xAxis,yAxis);
lineChart.setTitle("Woohoo, 2010");
lineChart.setAnimated(false);
series1.setName("Test 1");
series2.setName("test 2");
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
plot();
}
}, 0, 1000);
Scene scene = new Scene(lineChart,800,600);
xAxis.setCategories(myXaxis);
XYChart.Series XYSeries1 = new XYChart.Series(xyList1);
XYChart.Series XYSeries2 = new XYChart.Series(xyList2);
lineChart.getData().addAll(XYSeries1,XYSeries2);
i = 0;
stage.setScene(scene);
stage.show();
}
public void plot() {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
date.setTime(date.getTime() + i++ * 11111);
myXaxis.add(dateFormat.format(date));
System.out.println(myXaxis);
// with the line below uncommented the application breaks. Without the x-axis is updated as intended.
//xyList1.add(new XYChart.Data(dateFormat.format(date), Math.random()*10));
}
public static void main(String[] args) {
launch(args);
}
}
包应用;
导入java.text.simpleDataFormat;
导入java.util.array;
导入java.util.Date;
导入java.util.Timer;
导入java.util.TimerTask;
导入javafx.animation.animation;
导入javafx.animation.KeyFrame;
导入javafx.animation.Timeline;
导入javafx.application.application;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.chart.CategoryAxis;
导入javafx.scene.chart.LineChart;
导入javafx.scene.chart.NumberAxis;
导入javafx.scene.chart.StackedBarChart;
导入javafx.scene.chart.XYChart;
导入javafx.scene.layout.StackPane;
导入javafx.stage.stage;
导入javafx.util.Duration;
公共类主扩展应用程序{
最终XYChart.Series系列1=新的XYChart.Series();
最终的XYChart.Series系列2=新的XYChart.Series();
ObservableList xyList1=FXCollections.observableArrayList();
ObservableList xyList2=FXCollections.observableArrayList();
ObservableList myXaxis=FXCollections.observableArrayList();
int i;
@覆盖公共无效开始(阶段){
阶段。设置标题(“折线图样本”);
最终CategoryAxis xAxis=新CategoryAxis();
最终数字axis yAxis=新数字axis();
xAxis.setLabel(“月”);
最终堆叠条形图线形图=
新堆叠条形图(xAxis、yAxis);
线形图。设置标题(“Woohoo,2010”);
线形图。设置动画(假);
系列1.集合名称(“测试1”);
系列2.集合名称(“测试2”);
定时器=新定时器();
timer.scheduleAtFixedRate(新TimerTask(){
@凌驾
公开募捐{
plot();
}
}, 0, 1000);
场景=新场景(线形图,800600);
设置类别(myXaxis);
XYChart.Series XYSeries1=新的XYChart.Series(xyList1);
XYChart.Series XYSeries2=新的XYChart.Series(xyList2);
lineChart.getData().addAll(XYSeries1,XYSeries2);
i=0;
舞台场景;
stage.show();
}
公共无效绘图(){
SimpleDataFormat dateFormat=新的SimpleDataFormat(“HH:mm:ss”);
日期=新日期();
date.setTime(date.getTime()+i++*11111);
添加(dateFormat.format(date));
System.out.println(myXaxis);
//如果下面的行未注释,应用程序将中断。如果没有x轴,将按预期更新。
//添加(新的XYChart.Data(dateFormat.format(date),Math.random()*10));
}
公共静态void main(字符串[]args){
发射(args);
}
}
问题-从JavaFX应用程序线程对场景图节点进行可传递的修改
不要在主JavaFX应用程序线程之外修改场景节点(甚至是场景节点所依赖的可观察数据列表)(这是非法的,因为您收到的状态是非法状态异常)
计时器线程不会在JavaFX应用程序线程上运行
潜在修复
有几种方法可以解决此问题:
plot()
调用周围使用Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Platform.runLater(new Runnable() {
@Override public void run() {
plot();
}
});
}
}, 0, 1000);
Timeline timeline = new Timeline(
new KeyFrame(
Duration.ZERO,
new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent actionEvent) {
plot();
}
}
),
new KeyFrame(
Duration.seconds(1)
)
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
时间轴式解决方案
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Platform.runLater(new Runnable() {
@Override public void run() {
plot();
}
});
}
}, 0, 1000);
Timeline timeline = new Timeline(
new KeyFrame(
Duration.ZERO,
new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent actionEvent) {
plot();
}
}
),
new KeyFrame(
Duration.seconds(1)
)
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
时间线=新时间线(
新关键帧(
持续时间0.0,
新的事件处理程序
另一种选择是使用或与通过Platform.runLater()运行的和更新一起使用
。然而,这种解决方案虽然复杂且灵活,但比您描述的问题更复杂,应该首选简单的基于时间线或计时器的解决方案。如果每个脉冲导致执行耗时算法或大量时间,则更复杂的基于服务的解决方案是合适的关于基于网络或文件的I/O。当您将XYSeries1
和XYSeries2
添加到XYSeries1
和XYSeries2
中时,您是否注意到您的xysist1
和XYSeries2
中,而不是您可以使用的计时器。@ItachiUchiha是的,我注意到了。我已经尝试了其他方法,但似乎效果相反。