Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Charts 定期修改JavaFX StackedBarChart类别_Charts_Javafx - Fatal编程技术网

Charts 定期修改JavaFX StackedBarChart类别

Charts 定期修改JavaFX StackedBarChart类别,charts,javafx,Charts,Javafx,我试图找到一种方法来更新JavaFX CategoryAxis()的类别。我制作了一个可观察的类别列表,它们也会在plot()函数中进行更新。但是,如果我尝试向该系列添加一个新项,则会得到一个java.lang.IllegalStateException。虽然我知道,不是一个状态导致了错误,而且动态添加似乎是问题所在。下面我附上了我的代码 package application; import java.text.SimpleDateFormat; import java.util.Arra

我试图找到一种方法来更新JavaFX CategoryAxis()的类别。我制作了一个可观察的类别列表,它们也会在plot()函数中进行更新。但是,如果我尝试向该系列添加一个新项,则会得到一个java.lang.IllegalStateException。虽然我知道,不是一个状态导致了错误,而且动态添加似乎是问题所在。下面我附上了我的代码

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()
    调用周围使用
  • 使用JavaFX动画框架(the),它总是在JavaFX应用程序线程上运行它的所有代码
  • 在这两种选择中,我想我更喜欢第二种,但任何一种都可以

    计时器式解决方案

    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是的,我注意到了。我已经尝试了其他方法,但似乎效果相反。