2

我正在使用 JFreeChart 绘制几个 TimeSeries 图表。它似乎工作正常,但截至今天,所有图表似乎都在闪烁并且随机出现故障,使它们无法看到。如果我最小化和最大化,问题会在几秒钟内得到修复,直到下一次更新或单击鼠标。有谁知道问题可能是什么?

替代文字

代码非常简单:

TimeSeries ts = new TimeSeries("Graph", Millisecond.class);
TimeSeriesCollection dataset = new TimeSeriesCollection(ts);
JFreeChart Graph = createChart(dataset);
ChartPanel panel_Graph = new ChartPanel(Graph);

....

JFrame newWindow = new JFrame("Graph");
newWindow.setLayout(new GridLayout());
newWindow.setContentPane(panel_Graph);
newWindow.setMinimumSize(new Dimension(600, 480));
newWindow.setLocationRelativeTo(null);
newWindow.setVisible(true);


static private JFreeChart createChart(TimeSeriesCollection dataset) {
        JFreeChart chart = ChartFactory.createTimeSeriesChart(
            "Graph",
            "Time",
            "Value",
            dataset,
            false,
            true,
            false
        );
        final XYPlot plot = chart.getXYPlot();
        ValueAxis timeaxis = plot.getDomainAxis();
        timeaxis.setAutoRange(true);
        timeaxis.setFixedAutoRange(60000.0);
        return chart;
}
4

2 回答 2

1

如果您看到不一致/损坏的图像,有时表示更新了事件调度线程以外的线程上的数据集。我建议您添加一些断言语句来验证这一点:

断言 SwingUtilities.isEventDispatchThread();

另外,请注意,JFreeChart 并不是特别有效,因为它会在添加新数据点时重新呈现整个图形。您可以在此处进行的一项优化是:

  • 如果您的应用由多个图表组成,则只DatasetChangeEvent为当前显示的图表传播 s。如果图表被隐藏(例如在不同的选项卡上),则只需记录它已过时并且在选择选项卡时需要重新呈现的事实。

编辑

根据您对 Dan 的回复的评论,听起来您的 I/O 线程接收消息也在更新 JFreeChart 数据集,而实际上更新应该在事件调度线程上执行(并且消息应该在单独的 I/O 线程上执行)。为了实现这一点,我建议您使用基于节流阀的方法,将 I/O 事件存储在一起。您可以使用 aBlockingQueue来实现这一点;例如

// Message definition containing update information.
public interface Message { ... }

// BlockingQueue implementation used to enqueue updates received on I/O thread.
BlockingQueue<Message> msgQ = ...

// Method called by I/O thread when a new Message is received.
public void msgReceived(Message msg) {
  boolean wasEmpty = msgQ.isEmpty();

  msgQ.add(msg);

  // Queue was empty so need to re-invoke Swing thread to process queue.
  if (wasEmpty) {
    // processUpdates is a re-useable Runnable defined below.
    SwingUtilities.invokeLater(processUpdates);
  }
}

// Runnable that processes all enqueued events.  Much more efficient than:
// a) Creating a new Runnable each time.
// b) Processing one Message per call to run().
private final Runnable processUpdates = new Runnable() {
  public void run() {
    Message msg;

    while ((msg = msgQ.poll) != null) {
      // Add msg to dataset within Event Dispatch thread.
    }
  }
}
于 2009-10-13T13:28:30.873 回答
0

您如何将数据点添加到图表中?你是在 AWT 事件调度线程上做的吗?您可能应该使用SwingUtilities.invokeAndWait。您可以使用 invokeLater 但如果您的程序正忙于做其他事情,则 GUI 可能不会及时更新。

另外,你有多少数据点?我发现固定自动范围的代码对于大量数据点来说效率很低。这可能已在最新版本中修复(我不知道)。

于 2009-10-13T13:24:49.360 回答