0

I'm writing a program which would display incoming data while day. It's getting data about every 600 milliseconds and adding it to the TimeSeries Chart. The problem is: after about 10 minutes of work, GUI starts freezing. But if display only few series of 33 it's become fine. So maybe I am doing something wrong? How to solve that freezing? My SwingWorker may be weak, or chosen JFreeChart collection. Any tips might be helpful, thank you!

My short code example:

import java.awt.event.ActionEvent;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.ChartFactory;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.XYSeries;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYDataset;
import java.awt.Dimension;
import java.awt.Component;
import javax.swing.JCheckBox;
import org.jfree.chart.ChartPanel;
import java.awt.LayoutManager;
import java.awt.BorderLayout;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import java.awt.event.ActionListener;
import java.awt.Window;
import org.jfree.chart.ui.UIUtils;
import javax.swing.JPanel;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Paint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.SwingWorker;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

public class HideSeriesDemo1 extends ApplicationFrame {
    public HideSeriesDemo1(final String title) {
        super(title);
        this.setContentPane(new MyDemoPanel());
    }

    public static JPanel createDemoPanel() {
        return new MyDemoPanel();
    }

    public static void main(final String[] args) {
        final HideSeriesDemo1 demo = new HideSeriesDemo1("JFreeChart: HideSeriesDemo1.java");
        demo.pack();
        UIUtils.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }

    static class MyDemoPanel extends JPanel implements ActionListener {
        final JFreeChart chart;
        private JPanel boxPanel;
        TimeSeriesCollection seriesArray;
        private XYItemRenderer renderer;

        private void setLinesVisible() {
            for (int i = 0; i < seriesArray.getSeriesCount(); i++) {
                renderer.setSeriesVisible(i, true);
                JCheckBox box = (JCheckBox) boxPanel.getComponent(i);
                box.setSelected(true);
            }
        }

        private void setLinesInvisible() {
            for (int i = 0; i < seriesArray.getSeriesCount(); i++) {
                renderer.setSeriesVisible(i, false);
                JCheckBox box = (JCheckBox) boxPanel.getComponent(i);
                box.setSelected(false);
            }
        }

    private XYDataset createNumberedDataSet(int num) {
        seriesArray = new TimeSeriesCollection();

        for (int i = 0; i < num; i++) {
            int num2 = i + 1;
            TimeSeries s1 = new TimeSeries("Channel №" + num2);
            seriesArray.addSeries(s1);
        }
        return seriesArray;
    }

    public MyDemoPanel() {
        super(new BorderLayout());
        final XYDataset dataset = this.createNumberedDataSet(33);
        chart = this.createChart(dataset);
        final ChartPanel chartPanel = new ChartPanel(chart);
        boxPanel = new JPanel();
        boxPanel.setLayout(new GridLayout(0, 11));
        boxPanel.validate();
        for (int i = 0; i < 33; i++) {
            int numchik = i + 1;
            JCheckBox box1 = new JCheckBox("Channel №" + numchik);
            String com = "S" + numchik;
            box1.setSelected(true);
            box1.setActionCommand(com);
            box1.addActionListener(this);
            boxPanel.add(box1);
        }
        boxPanel.validate();
        final JButton btn = new JButton("All not sellected");
        btn.setVisible(true);
        btn.setActionCommand("btn");
        btn.addActionListener(this);
        boxPanel.add(btn);
        final JButton btn2 = new JButton("All sellected");
        btn2.setVisible(true);
        btn2.setActionCommand("btn2");
        btn2.addActionListener(this);
        boxPanel.add(btn2);

        final JButton btn3 = new JButton("SwingWorker?");
        btn3.setVisible(true);
        btn3.setActionCommand("btn3");
        btn3.addActionListener(this);
        boxPanel.add(btn3);
        this.add(chartPanel);
        this.add(boxPanel, "South");
        JPopupMenu pop = chartPanel.getPopupMenu();
        pop.add(new JSeparator());
        JMenuItem remBtn = new JMenuItem("All not selected");
        remBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                setLinesInvisible();
            }
        });
        pop.add(remBtn);
        JMenuItem addBtn = new JMenuItem("All visible");
        addBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                setLinesVisible();
            }
        });
        pop.add(addBtn);
    }

    private JFreeChart createChart(final XYDataset dataset) {
        final JFreeChart chart = ChartFactory.createTimeSeriesChart("xDisplay", "Time", "Data", dataset, true, true, false);
        final XYPlot plot = (XYPlot) chart.getPlot();
        this.renderer = plot.getRenderer();
        return chart;
    }
    @Override
    public void actionPerformed(final ActionEvent e) {
        int series = -1;
        if (e.getActionCommand().equals("btn")) {

            this.setLinesInvisible();
            System.out.println("set invisible btn pressed");
            boxPanel.validate();

            // System.out.println("btn pressed");
            return;
        }
        if (e.getActionCommand().equals("btn2")) {
            setLinesVisible();
            boxPanel.validate();
            System.out.println("setBtnVisible pressed");
            return;
        }
        if (e.getActionCommand().equals("btn3")) {
            System.out.println("swingworker");
            MySwingWorker swi = new MySwingWorker();
            swi.execute();
        }
               for (int i = 0; i<33;i++){
            String s="S"+i;
           if (e.getActionCommand().equals(s)) {
               series = i-1;
           }
        }
        if (series >= 0) {
            final boolean visible = this.renderer.getItemVisible(series, 0);
            this.renderer.setSeriesVisible(series, !visible);
        }
    }

    private class MySwingWorker extends SwingWorker<Boolean, double[]> {
        LinkedList<Double> fifo = new LinkedList<Double>();

        public MySwingWorker() {
            fifo.add(0.0);
        }

        @Override
        protected Boolean doInBackground() {
            while (!isCancelled()) {
                try {
                    Thread.sleep(600);
                } catch (InterruptedException ex) {
                    Logger.getLogger(HideSeriesDemo1.class.getName()).log(Level.SEVERE, null, ex);
                }
                fifo.add(fifo.get(fifo.size() - 1) + Math.random() - .5);
                if (fifo.size() > 1000) {
                    fifo.removeFirst();
                }
                double[] array = new double[fifo.size()];
                for (int i = 0; i < fifo.size(); i++) {
                    array[i] = fifo.get(i);
                }
                System.out.println(array.length + " : " + Arrays.toString(array) + "Array: ");
                publish(array);
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    // eat it. caught when interrupt is called
                    System.out.println("MySwingWorker shut down." + " name:" + Thread.currentThread().getName());
                }
            }
            return true;
        }

        @Override
        protected void process(List<double[]> chunks) {
            double[] mostRecentDataSet = chunks.get(chunks.size() - 1);
            for (int i = 0; i < seriesArray.getSeriesCount(); i++) {
                TimeSeries series = seriesArray.getSeries(i);
                series.addOrUpdate(new Millisecond(), mostRecentDataSet[0] + i);
            }
            fifo.removeFirst();

            System.out.println(" repaint zone " + " name:" + Thread.currentThread().getName());
        }
    }
}
}
Abra
  • 19,142
  • 7
  • 29
  • 41
Sashok
  • 1
  • 2
  • 2
    *"My short code example:"* It's almost 350 lines of code! Interesting definition of 'short'.. – Andrew Thompson Jan 21 '21 at 11:36
  • @ Andrew Thompson , idk, I remove some useless stuff to make it shorter – Sashok Jan 21 '21 at 11:52
  • Your implementation of `main()` seems to violate the rule in [*Initial Threads*](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html); also try [`CheckThreadViolationRepaintManager`](https://stackoverflow.com/a/7788806/230513) and `setMaximumItemCount()`, seen [here](https://stackoverflow.com/a/65660630/230513). – trashgod Jan 22 '21 at 00:03
  • The [profile](http://stackoverflow.com/q/2064427/230513) is nominal using Java 1.8, JFreeChart 1.5.2 at 15+ minutes; 1000 * 60 * 15 * 33 = 29,700,000 data points is unrealistic; consider [paging](https://stackoverflow.com/a/6849654/230513). – trashgod Jan 22 '21 at 17:32
  • Cross-posted [here](https://www.jfree.org/forum/viewtopic.php?f=3&t=120997). – trashgod Feb 04 '21 at 23:37

0 Answers0