Java 使用JFreeChart的故障图

Java 使用JFreeChart的故障图,java,graph,jfreechart,Java,Graph,Jfreechart,我正在使用JFreeChart绘制多个TimeSeries图表。它似乎工作得很好,但到今天为止,所有的图形似乎都在闪烁,并且随机地闪烁,使它们不可能被看到。如果我最小化和最大化,问题会在几秒钟内得到修复,直到下一次更新或鼠标单击。有人知道问题可能是什么吗 代码非常简单: TimeSeries ts = new TimeSeries("Graph", Millisecond.class); TimeSeriesCollection dataset = new TimeSeriesCollecti

我正在使用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;
}

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


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

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

断言SwingUtilities.isEventDispatchThread()

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

  • 如果您的应用程序由多个图表组成,则仅为当前显示的图表传播
    DatasetChangeEvent
    s。如果某个图表被隐藏(例如,在不同的选项卡上),则只需记录该图表过时的事实,并在选择该选项卡时需要重新提交
编辑

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

// 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.
    }
  }
}
//包含更新信息的消息定义。
公共接口消息{…}
//BlockingQueue实现,用于将I/O线程上接收的更新排队。
BlockingQueue msgQ=。。。
//方法,该方法在收到新消息时由I/O线程调用。
public void msgReceived(消息msg){
布尔值waspempy=msgQ.isEmpty();
添加(味精);
//队列为空,所以需要重新调用Swing线程来处理队列。
如果(为空){
//processUpdates是下面定义的可重用可运行程序。
调用器(processUpdates);
}
}
//处理所有排队事件的Runnable。效率远高于:
//a)每次创建一个新的Runnable。
//b)每次调用run()处理一条消息。
private final Runnable processUpdates=new Runnable(){
公开募捐{
消息消息;
while((msg=msgQ.poll)!=null){
//将消息添加到事件调度线程内的数据集。
}
}
}

为什么要将XYPlot标记为final?嗯,这只是在互联网上尝试解决问题的不同解决方案的遗留问题。删除它没有什么区别。我有一个单独的线程,它从另一个节点接收消息,并向序列中添加两个值:ts.addOrUpdate(new millished(),Update);在一种情况下,新数据点每10秒到达一次,而在另一种情况下,新数据点每秒最多到达5次。但是,两者似乎都遇到了相同的问题。此外,对于间隔10秒的更新,第一个数据点直到第二个数据点到达后才显示,然后两个数据点都可见。接收消息的线程需要将时间序列更新整理到事件调度线程上。我建议使用SwingUtilities.invokeLater来防止UI更新时I/O线程阻塞。我不确定问题到底出在哪里,因为我刚刚在另一台计算机上运行了该程序,看起来还不错。可能是库损坏了吗?问题已经解决了!似乎与我的图形驱动程序有冲突。我添加了以下标志,到目前为止没有任何问题:-Dsun.java2d.opengl=trueI已经放置了assert SwingUtilities.isEventDispatchThread();就在数据集在接收到消息后被更新的点之上,这似乎没有任何区别。而且,如果我单击图形(不拖动或任何操作),问题会变得更糟。现在,我只是打开一个新的JFrame来显示图形,但是标签式的想法听起来也不错。但是,即使只有一个图是打开的,也会出现问题。它以前不会发生,现在也会发生,即使我使用了较旧版本的代码。虽然您的消息处理实现比我所做的要高效得多,但它似乎对绘图部分没有任何影响。我使用了带有invokeLater的LinkedBlockingQueue,但仍然得到了损坏的图形。