Проблема с шаблоном Observer и гистограммой с использованием JavaFX - PullRequest
0 голосов
/ 13 октября 2018

У меня проблема, я бы хотел, чтобы гистограмма с сериями автоматически обновлялась с помощью Observer Pattern.Проблема в том, что при вызове функции обновления ничто не добавляется на график.Вот код, который я использую: Первый класс - это класс, который предоставляет мне мои данные.

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 javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;

import java.util.Observable;
import java.util.Observer;

public class MyBarChart extends Application implements Observer {

private String[] dataName;
private double[] data;
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();
}

@Override
public void update(Observable o, Object arg) {
    if(o instanceof ChartModel){
        ChartModel cm=(ChartModel) o;
        dataName=cm.getDataName();
        data=cm.getData();
        for(int i=0; i<dataName.length; i++){
            System.out.println(dataName[i]+ " " +data[i]);
        }
        bc.getData().clear();
        for(int i=0; i<dataName.length; i++){
            XYChart.Series series1 = new XYChart.Series();
            series1.setName(dataName[i]);
            series1.getData().add(new XYChart.Data(data[i], dataName[i]));
            bc.getData().addAll(series1);
        }
    }
}

public static void main(String[] args){
    String[] dataName=new String[]{"Informatique","Infirmier","Kine", "Compta"};
    double[] data=new double[]{10,20,30,40};
    ChartModel cm=new ChartModel();
    launch(args);
    cm.setChartData(dataName, data);
    MyBarChart bc=new MyBarChart();
    cm.addObserver(bc);
    //cm.updateCharData("Informatique", 50);
/*        try{
        Thread.sleep(5000);
    }
    catch (InterruptedException e){//trt
        }
        cm.updateCharData("Informatique", 10);
    try{ Thread.sleep(5000); }
    catch (InterruptedException e){//trt
         }*/
  }
}

Знаете ли вы, что я могусделать, чтобы решить это?

Большое спасибо.

1 Ответ

0 голосов
/ 13 октября 2018

(упрощенный) жизненный цикл приложения JavaFX выглядит следующим образом: вызывается

  1. Application.launch, и это запускает инструментарий ect.
    1. Создается экземпляр используемого класса Application.
    2. Повторная обработка события / рендеринг / макет и т. Д.
  2. Когда JavaFX определяетон должен выключиться, выполнить некоторую очистку и Application.launch возвращает.

По этой причине код в методе main после

launch(args);

выполняется после закрытия GUI.
Кроме того, поскольку Application.launch создает свой собственный экземпляр класса приложения, обновления графического интерфейса не будет.(Вы добавляете другой экземпляр в качестве наблюдателя).

Также обратите внимание, что ваше приложение зависает, пока выполняется длинная операция в потоке приложения JavaFX.По этой причине вам необходимо убедиться, что обновления модели выполняются в отдельном потоке.Это также требует, чтобы вы гарантировали, что обновления GUI выполняются в потоке приложения JavaFX (из соображений производительности JavaFX предполагает, что доступ к GUI осуществляется только из этого потока.).


Некоторые части вашего ChartModel класс кажется странным:

  • data - это static, но dataName - это не
  • Вы, кажется, заново изобретаете колесо: вместо этого вы можете просто использовать LinkedHashMap<String, Double>использования 2 массивов для хранения данных
  • доступ к данным не синхронизирован, что приводит к потенциальным проблемам параллелизма
  • 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);
    }
}
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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...