从线程更新 JFreeChart

Update JFreeChart from thread

我必须构建一个 GPS 解析器。我需要在另一个线程中解析 NMEA 字符串,该线程将解析单个 NMEA 字符串并以 1 Hz 的频率更新图表。现在我构建了部分代码,但我在 while 循环中解析主线程中的数据;我的老师说那是错误的。我在 Java 上编写了一些程序,但不是在多线程方面。如何将解析过程和刷新图表移动到后台线程?

public class MainFrame extends JFrame {

    private JButton btnWybPlik;
    private JLabel jlDroga;
    private JLabel jlPredkosc;
    private JLabel jlCzas;
    private JPanel mainjpanel;
    private JPanel jpMenu;
    private JPanel jpTablica;

    //private String sciezkaPliku;
    private SekwencjaGGA sekGGA = null;
    private SekwencjaGGA popSekGGA = null;
    private SekwencjaGSA sekGSA;
    private SekwencjaGLL sekGLL;
    private SekwencjaRMC sekRMC;

    private double droga;
    private double predkosc;

    private XYSeries series1;
    private XYSeriesCollection dataset;

    public MainFrame() {
        droga = 0;
        btnWybPlik.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
                int result = fileChooser.showOpenDialog(mainjpanel);
                if (result == JFileChooser.APPROVE_OPTION) {
                    File selectedFile = fileChooser.getSelectedFile();
                    //System.out.println("Selected file: " + selectedFile.getAbsolutePath());
                    String sciezkaPliku = selectedFile.getAbsolutePath();
                    wczytaniePliku(sciezkaPliku);
                }
            }
        });

        jpTablica = new JPanel();
        mainjpanel.add(jpTablica);

        this.series1 = new XYSeries("Trasa", false);

        final XYSeriesCollection dataset = new XYSeriesCollection(this.series1);
        final JFreeChart chart = createChart(dataset);
        final ChartPanel chartPanel = new ChartPanel(chart);
        jpTablica.add(chartPanel);
    }

    private void wczytaniePliku(String sciezkaDoPliku) {
        try (BufferedReader br = new BufferedReader(new FileReader(sciezkaDoPliku))) {
            String line;
            //series1.add(53.448, 14.4907);
            while ((line = br.readLine()) != null) {
                parseLine(line);
            }
            //series1.add(53.4485, 14.4910);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void parseLine(String line) {
        String bezSumKont = line.substring(0, line.length() - 3);
        List<String> podzSekw = Arrays.asList(bezSumKont.split(","));

        if (podzSekw.get(0).equalsIgnoreCase("$GPGGA")) {
            if (check(line)) {
                if (sekGGA != null)
                    popSekGGA = sekGGA;

                sekGGA = new SekwencjaGGA(podzSekw);
                if (popSekGGA != null) {
                    droga += obliczOdleglosc(popSekGGA, sekGGA);
                    jlDroga.setText(String.valueOf(droga));
                }

                series1.add(sekGGA.getWspolzedne().getLongitude(), sekGGA.getWspolzedne().getLatitude());
                System.out.println(sekGGA.getWspolzedne().getLatitude() + " " + sekGGA.getWspolzedne().getLongitude());
                //System.out.println(series1.getMaxY() + " " + series1.getMinY());
            } else {
                //TODO: Zlicz błąd
            }
        }
        if (podzSekw.get(0).equalsIgnoreCase("$GPGSA")) {
            if (check(line)) {
                sekGSA = new SekwencjaGSA(podzSekw);
            } else {
                //TODO: Zlicz błąd
            }
        }
        if (podzSekw.get(0).equalsIgnoreCase("$GPGLL")) {
            if (check(line)) {
                sekGLL = new SekwencjaGLL(podzSekw);
            } else {
                //TODO: Zlicz błąd
            }
        }
        if (podzSekw.get(0).equalsIgnoreCase("$GPRMC")) {
            //TODO: Sekwencja RMC (Recommended minimum of data)
            if (check(line)) {
                sekRMC = new SekwencjaRMC(podzSekw);
            } else {
                //TODO: Zlicz błąd
            }
        }
    }

    private double obliczOdleglosc(SekwencjaGGA pkt1, SekwencjaGGA pkt2) {
        double odleglosc = 0;

        double earthRadius = 6371000; //meters
        double dLat = Math.toRadians(pkt2.getWspolzedne().getLatitude() - pkt1.getWspolzedne().getLatitude());
        double dLng = Math.toRadians(pkt2.getWspolzedne().getLongitude() - pkt1.getWspolzedne().getLongitude());
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())) * Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())) *
                        Math.sin(dLng / 2) * Math.sin(dLng / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        odleglosc = earthRadius * c;

        return odleglosc;
    }

    /**
     * Funkcja sprawdzająca sume kontrolną
     *
     * @param tekst cała linia NMEA
     * @return true jeśli się suma kontrolna zgadza
     */
    private boolean check(String tekst) {
        String suma = tekst.substring(tekst.length() - 2, tekst.length());
        tekst = tekst.substring(1, tekst.length() - 3);

        int checksum = 0;
        for (int i = 0; i < tekst.length(); i++) {
            checksum = checksum ^ tekst.charAt(i);
        }

        if (Integer.parseInt(suma, 16) == checksum) {
            return true;
        }

        return false;
    }

    private JFreeChart createChart(final XYDataset dataset) { ... }

    private void customizeChart(JFreeChart chart) { ... }    

    public static void main(String[] args) {
        JFrame frame = new JFrame("MainFrame");
        frame.setContentPane(new MainFrame().mainjpanel);
        frame.setPreferredSize(new Dimension(640, 480));
        frame.pack();
        frame.setVisible(true);
    }

避免阻塞event dispatch thread, construct an instance of SwingWorker. Collect data in your implementation of doInBackground(), publish() intermediate results, and update the XYSeries in your implementation of process(). The listening chart will update itself in response. A related example that uses is seen below and examined here