2

我想在 x 轴上显示实时数据的 TimeSeries 图表上显示实时数据(或者至少具有与实时相同的时间速度)。

这是随机数作为实时输入的问题的 SSCCE。x 轴上显示的时间比实时快得多(假设它以 hh:mm:ss 格式显示):

public class DynamicTimeSeriesChart extends JPanel {

    private DynamicTimeSeriesCollection dataset;
    private JFreeChart chart = null;

    public DynamicTimeSeriesChart(final String title) {

        dataset = new DynamicTimeSeriesCollection(1, 2000, new Second());
        dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 1990)); // date 1st jan 0 mins 0 secs

        dataset.addSeries(new float[1], 0, title);
        chart = ChartFactory.createTimeSeriesChart(
            title, "Time", title, dataset, true,
            true, false);
        final XYPlot plot = chart.getXYPlot();

        ValueAxis axis = plot.getDomainAxis();
        axis.setAutoRange(true);
        axis.setFixedAutoRange(200000); // proportional to scroll speed
        axis = plot.getRangeAxis();

        final ChartPanel chartPanel = new ChartPanel(chart);
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        add(chartPanel);
    }

    public void update(float value) {
        float[] newData = new float[1];
        newData[0] = value;
        dataset.advanceTime();
        dataset.appendData(newData);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final DynamicTimeSeriesChart chart = new DynamicTimeSeriesChart("random numbers");
        frame.add(chart);
        frame.pack();
        frame.setVisible(true);
        Timer timer = new Timer(100, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        chart.update((float) (Math.random() * 10));
                    }
                });
            }
        });
        timer.start();
    }
}
4

1 回答 1

4

虽然sleep()初始线程上是可以接受的,但 Swing GUI 对象应该在事件分派线程上构建和操作。相反,请使用 a来调整更新速度,如此javax.swing.Timer所示。100 ms的 A将以大约 10 Hz 的频率更新。delay

如果漂移不可接受,则以标称速率的一半从另一个线程轮询主机时钟,并使用EventQueue.invokeLater(). 确保主机与 NTP 服务器同步。

附录:根据您的更新,请注意所有Swing GUI 对象必须在事件调度线程上构建和操作,而不仅仅是javax.swing.Timer. Swing 的优点Timer是它在 EDT 上触发。下面的变化显示了大约实时的 10 秒 1 Hz 数据。

附录:您可以调整传递到的时间,如下setTimeBase()所示

图片

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;

/**
 * @see https://stackoverflow.com/a/21307289/230513
 */
public class DynamicTimeSeriesChart extends JPanel {

    private final DynamicTimeSeriesCollection dataset;
    private final JFreeChart chart;

    public DynamicTimeSeriesChart(final String title) {
        dataset = new DynamicTimeSeriesCollection(1, 1000, new Second());
        dataset.setTimeBase(new Second(0, 0, 0, 23, 1, 2014));
        dataset.addSeries(new float[1], 0, title);
        chart = ChartFactory.createTimeSeriesChart(
            title, "Time", title, dataset, true, true, false);
        final XYPlot plot = chart.getXYPlot();
        DateAxis axis = (DateAxis) plot.getDomainAxis();
        axis.setFixedAutoRange(10000);
        axis.setDateFormatOverride(new SimpleDateFormat("ss.SS"));
        final ChartPanel chartPanel = new ChartPanel(chart);
        add(chartPanel);
    }

    public void update(float value) {
        float[] newData = new float[1];
        newData[0] = value;
        dataset.advanceTime();
        dataset.appendData(newData);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame("testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                final DynamicTimeSeriesChart chart
                    = new DynamicTimeSeriesChart("Alternating data");
                frame.add(chart);
                frame.pack();
                Timer timer = new Timer(1000, new ActionListener() {
                    private boolean b;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        chart.update(b ? 1 : 0);
                        b = !b;
                    }
                });
                timer.start();
                frame.setVisible(true);
            }
        });
    }
}
于 2014-01-23T11:49:02.860 回答