使用JavaFX的观察者模式和条形图存在问题

使用JavaFX的观察者模式和条形图存在问题,java,javafx,observer-pattern,Java,Javafx,Observer Pattern,我有一个问题,我想有一个系列的条形图自动更新与观察员模式。问题是:当调用update函数时,在图表上没有附加任何内容。以下是我使用的代码: 第一个类是为我提供数据的类 import java.util.Observable; public class ChartModel extends Observable { private String[] dataName; private static double[] data; public ChartModel(){

我有一个问题,我想有一个系列的条形图自动更新与观察员模式。问题是:当调用update函数时,在图表上没有附加任何内容。以下是我使用的代码: 第一个类是为我提供数据的类

import java.util.Observable;

public class ChartModel extends Observable {
    private  String[] dataName;
    private static double[] data;

    public ChartModel(){
        dataName=new String[4];
        data=new double[4];
    }

    public String[] getDataName(){
        return dataName;
    } 

    public double[] getData(){
        return data;
    }

    public void setChartData(String[] d, double[] dd){
        for(int i=0; i<dataName.length; i++){
            dataName[i]=d[i];
            data[i]=dd[i];
        }
        setChanged();
        notifyObservers();
    }

    public void updateCharData(String dataName, double newData){
        int i;
        for(i=0; i<dataName.length() && !this.dataName[i].equals(dataName); i++);
        if(i<dataName.length())
            data[i]=newData;
        setChanged();
        notifyObservers();
    }
}
import java.util.Observable;
公共类ChartModel扩展了Observable{
私有字符串[]数据名;
私有静态双[]数据;
公共图表模型(){
dataName=新字符串[4];
数据=新的双精度[4];
}
公共字符串[]getDataName(){
返回数据名;
} 
public double[]getData(){
返回数据;
}
公共void setChartData(字符串[]d,双[]dd){
对于(int i=0;i,JavaFX应用程序的(简化)生命周期如下:

  • 调用
    Application.launch
    ,启动工具包ect。
  • 创建所使用的
    应用程序
    类的实例
  • 重复事件处理/渲染/布局等
  • 当JavaFX确定应该关闭时,它会进行一些清理,并
    应用程序。launch
    返回
  • 因此,主方法中的代码

    launch(args);
    
    在GUI关闭后执行。
    此外,由于
    Application.launch
    创建了自己的应用程序类实例,因此不会对GUI进行任何更新。(您将添加一个不同的实例作为观察者)

    还请注意,只要JavaFX应用程序线程上的longrunning操作正在运行,应用程序就会冻结。因此,您需要确保在单独的线程上完成对模型的更新。这还要求您确保在JavaFX应用程序线程上完成对GUI的更新(出于性能原因,JavaFX假定仅从该线程访问GUI。)


    ChartModel
    类的某些部分似乎很奇怪:

    • 数据
      静态的
      ,但
      数据名
      不是
    • 您似乎重新发明了轮子:您可以简单地使用
      LinkedHashMap
      而不是使用两个数组来存储数据
    • 对数据的访问未同步,导致潜在的并发问题
    • Observable
      在Java 9中被弃用
    • updateCharData
      中,字符串参数的长度用于循环条件和
      if
      条件
    下面的代码演示如何从
    start
    方法启动更新,并从单独的线程执行更新。它还更改了数据存储到
    LinkedHashMap
    的方式,以避免实现类似映射的功能

    public class MyBarChart extends Application implements Observer {
        BarChart<String, Number> bc;
    
        public void start(Stage stage) {
            stage.setTitle("Graphique");
            final CategoryAxis xAxis = new CategoryAxis();
            final NumberAxis yAxis = new NumberAxis();
            bc = new BarChart<String, Number>(xAxis, yAxis);
            bc.setTitle("Etudiants");
            xAxis.setLabel("Sections");
            //xAxis.setTickLabelRotation(90);
            yAxis.setLabel("Nombre d'élèves");
    
            Scene scene = new Scene(bc, 800, 600);
            stage.setScene(scene);
            stage.show();
    
            initModel();
        }
    
        private void initModel() {
            String[] dataName = new String[]{"Informatique", "Infirmier", "Kine", "Compta"};
            double[] data = new double[]{10, 20, 30, 40};
            ChartModel cm = new ChartModel();
            cm.setChartData(dataName, data);
            cm.addObserver(this);
            new Thread(() -> {
                cm.updateCharData("Informatique", 50);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {//trt
                }
                cm.updateCharData("Informatique", 10);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {//trt
                }
            }).start();
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof ChartModel) {
                ChartModel cm = (ChartModel) o;
                Map<String, Double> data = cm.getData();
    
                // make sure to read the data from the thread that does the updates
                // or make sure the data is synchronized
    
                final XYChart.Series<String, Number>[] series = new XYChart.Series[data.size()];
    
                int index = 0;
                for (Map.Entry<String, Double> entry : cm.getData().entrySet()) {
                    XYChart.Series<String, Number> series1 = new XYChart.Series<>();
                    series1.setName(entry.getKey());
                    series1.getData().add(new XYChart.Data<>(entry.getKey(), entry.getValue()));
                    series[index] = series1;
                    index++;
                }
    
                // updates to the gui on the javafx application thread
                Platform.runLater(() -> bc.getData().setAll(series));
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    公共类MyBarChart扩展了应用程序{
    柱状图bc;
    公众假期开始(阶段){
    舞台布景标题(“笔画”);
    最终CategoryAxis xAxis=新CategoryAxis();
    最终数字axis yAxis=新数字axis();
    bc=新条形图(xAxis,yAxis);
    bc.setTitle(“受试者”);
    xAxis.setLabel(“章节”);
    //xAxis.setticklabel旋转(90);
    yAxis.setLabel(“Nombre d'lèves”);
    场景=新场景(bc,800600);
    舞台场景;
    stage.show();
    initModel();
    }
    私有void initModel(){
    字符串[]数据名=新字符串[]{“Informatique”、“Infirmier”、“Kine”、“Compta”};
    double[]数据=新的double[]{10,20,30,40};
    ChartModel cm=新的ChartModel();
    cm.setChartData(数据名、数据);
    cm.addObserver(本);
    新线程(()->{
    cm.updateCharData(“Informatique”,50);
    试一试{
    睡眠(5000);
    }捕获(中断异常e){//trt
    }
    cm.updateCharData(“Informatique”,10);
    试一试{
    睡眠(5000);
    }捕获(中断异常e){//trt
    }
    }).start();
    }
    @凌驾
    公共无效更新(可观察o,对象arg){
    if(图表模型的o实例){
    ChartModel cm=(ChartModel)o;
    Map data=cm.getData();
    //确保从执行更新的线程读取数据
    //或者确保数据同步
    最终的XYChart.Series[]Series=新的XYChart.Series[data.size()];
    int指数=0;
    对于(Map.Entry:cm.getData().entrySet()){
    XYChart.Series系列1=新的XYChart.Series();
    series1.setName(entry.getKey());
    series1.getData().add(新的XYChart.Data(entry.getKey(),entry.getValue());
    系列[索引]=系列1;
    索引++;
    }
    //javafx应用程序线程上的gui更新
    Platform.runLater(()->bc.getData().setAll(series));
    }
    }
    公共静态void main(字符串[]args){
    发射(args);
    }
    }
    
    公共类ChartModel扩展了Observable{
    私有最终映射数据=新LinkedHashMap();
    公共地图getData(){
    返回数据;
    }
    公共void setChartData(字符串[]d,双[]dd){
    如果(d.长度!=dd.长度){
    抛出新的IllegalArgumentException();
    }
    对于(int i=0;i
    首先,感谢您的回答和对JavaFX应用程序生命周期的解释。对于奇怪的部分:-静态:我犯了一个错误,我不知道为什么我说我可能累了哈哈。-对于hashmap:我想使用一个,但为了先测试我的应用程序,我使用了两个数组,并想在之后升级到hashmap。-Yo你的数据是正确的
    public class MyBarChart extends Application implements Observer {
        BarChart<String, Number> bc;
    
        public void start(Stage stage) {
            stage.setTitle("Graphique");
            final CategoryAxis xAxis = new CategoryAxis();
            final NumberAxis yAxis = new NumberAxis();
            bc = new BarChart<String, Number>(xAxis, yAxis);
            bc.setTitle("Etudiants");
            xAxis.setLabel("Sections");
            //xAxis.setTickLabelRotation(90);
            yAxis.setLabel("Nombre d'élèves");
    
            Scene scene = new Scene(bc, 800, 600);
            stage.setScene(scene);
            stage.show();
    
            initModel();
        }
    
        private void initModel() {
            String[] dataName = new String[]{"Informatique", "Infirmier", "Kine", "Compta"};
            double[] data = new double[]{10, 20, 30, 40};
            ChartModel cm = new ChartModel();
            cm.setChartData(dataName, data);
            cm.addObserver(this);
            new Thread(() -> {
                cm.updateCharData("Informatique", 50);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {//trt
                }
                cm.updateCharData("Informatique", 10);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {//trt
                }
            }).start();
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof ChartModel) {
                ChartModel cm = (ChartModel) o;
                Map<String, Double> data = cm.getData();
    
                // make sure to read the data from the thread that does the updates
                // or make sure the data is synchronized
    
                final XYChart.Series<String, Number>[] series = new XYChart.Series[data.size()];
    
                int index = 0;
                for (Map.Entry<String, Double> entry : cm.getData().entrySet()) {
                    XYChart.Series<String, Number> series1 = new XYChart.Series<>();
                    series1.setName(entry.getKey());
                    series1.getData().add(new XYChart.Data<>(entry.getKey(), entry.getValue()));
                    series[index] = series1;
                    index++;
                }
    
                // updates to the gui on the javafx application thread
                Platform.runLater(() -> bc.getData().setAll(series));
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    public class ChartModel extends Observable {
    
        private final Map<String, Double> data = new LinkedHashMap<>();
    
        public Map<String, Double> getData() {
            return data;
        }
    
        public void setChartData(String[] d, double[] dd) {
            if (d.length != dd.length) {
                throw new IllegalArgumentException();
            }
            for (int i = 0; i < d.length; i++) {
                data.put(d[i], dd[i]);
            }
            setChanged();
            notifyObservers();
        }
    
        public void updateCharData(String dataName, double newData) {
            data.put(dataName, newData);
            setChanged();
            notifyObservers();
        }
    }