Update JFreeChart from thread

394 views Asked by At

I have to build a GPS parser. I need to parse the NMEA string in another thread, which will be parsing a single NMEA string and update chart at 1 Hz. For now I build part of my code, but I parse data in main thread in while loop; my teacher said that is wrong. I was programming some on Java but not in multi-threading aspects. How I could move parsing process and refreshing chart to background thread?

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);
    }
1

There are 1 answers

0
trashgod On BEST ANSWER

To avoid blocking the 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.

image