使用jFreeChart的多个图形中的多个图形

我试图使用jFreechart生成两个图形,每个图形有12个图形(在jFreeChart中称为系列)。 然而,一些图表被简单地跳过了! 我知道我在这里有同步问题,并试图使用用户@trashgod 在这里提供给我的方法但是我失败了。 我知道我使用swingworker的方式是错误的 ! 我不知道如何解决它

每个图应包含10个平行水平直线的图。 正如您在附图中看到的那样,缺少一些线条。 这两个数字也必须相同(不是)。 在实践中,我将不得不在不同时间在我的应用程序的几个位置生成多个图形(每个图形之间的随机时间间隔甚至是各个图形的图形)任何帮助都将非常感谢

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: This dataset already contains a series with the key Plot 11 at org.jfree.data.xy.XYSeriesCollection.addSeries(XYSeriesCollection.java:154) at swing.FastChart2$MySwingWorker.process(FastChart2.java:192) at javax.swing.SwingWorker$3.run(SwingWorker.java:414) at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112) at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832) at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112) at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842) at javax.swing.Timer.fireActionPerformed(Timer.java:312) at javax.swing.Timer$DoPostEvent.run(Timer.java:244) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733) at java.awt.EventQueue.access$200(EventQueue.java:103) at java.awt.EventQueue$3.run(EventQueue.java:694) at java.awt.EventQueue$3.run(EventQueue.java:692) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:703) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.run(EventDispatchThread.java:91) 

在此处输入图像描述

 package swing; import java.awt.BorderLayout; import java.awt.Color; import java.awt.EventQueue; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.Ellipse2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingWorker; import org.jfree.chart.*; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.util.ShapeUtilities; public class FastChart2 extends JFrame { private XYSeries [] xySeries ; private XYPlot xyPlot; private XYSeriesCollection xySeriesCollection; private String title; private static int instanceNum=0; private int figNum=0; private ChartPanel chartPanel; public FastChart2(String s) { super(s); figNum = instanceNum; instanceNum++; init(s); } private void init(String s){ title = s; xySeries = new XYSeries[12]; for (int i = 0; i < xySeries.length; i++) { xySeries[i] = new XYSeries("Plot "+i); } xySeriesCollection = new XYSeriesCollection(); JFreeChart chart = ChartFactory.createScatterPlot( title, "X", "Y", xySeriesCollection, PlotOrientation.VERTICAL, true, true, false); xyPlot = chart.getXYPlot(); xyPlot.setDomainCrosshairVisible(true); xyPlot.setRangeCrosshairVisible(true); chartPanel = createChartPanel(chart); add(chartPanel, BorderLayout.CENTER); JPanel control = new JPanel(); add(control, BorderLayout.SOUTH); setDefaultCloseOperation(DISPOSE_ON_CLOSE); pack(); setLocationRelativeTo(null); setVisible(true); } private ChartPanel createChartPanel(JFreeChart chart) { XYItemRenderer renderer = xyPlot.getRenderer(); renderer.setSeriesPaint(0, Color.magenta); renderer.setSeriesPaint(1, Color.green); renderer.setSeriesPaint(2, Color.blue); renderer.setSeriesPaint(4, Color.black); renderer.setSeriesPaint(3, Color.yellow); Shape cross = ShapeUtilities.createDiagonalCross(3, 0); Shape plus = ShapeUtilities.createRegularCross(4,0); for (int i = 0; i <=3; i++) { renderer.setSeriesShape(0+i, new Rectangle(-1, -1, 2, 2)); renderer.setSeriesShape(4+i, new Ellipse2D.Float(-2F, -2F, 5F, 5F)); renderer.setSeriesShape(8+i, cross); } NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis(); domain.setRange(0,1000); NumberAxis range = (NumberAxis) xyPlot.getRangeAxis(); range.setRange(0,1200); return new ChartPanel(chart); } public void multiPlot(){ Thread thread = null; thread = new Thread (){ public void run() { final double [] x = new double[1000]; final double [] y = new double[1000]; try{ for (int k = 0; k < 12; k++) { for (int i = 0; i < y.length; i++) { x[i] = i; y[i] = k*100; } try { Thread.sleep(100); } catch (InterruptedException e) { } plot2d(k % 12, x, y," Fig:"+figNum+" Seri:"+k); } } catch (Exception e){ System.out.println(); } } }; thread.start(); } public synchronized void plot2d( final int iSeriesN, final double [] dX, final double [] dY, final String sT){ if (dY.length != dX.length){ throw new IllegalArgumentException("Error! inputs x and y have to be of same size."); } MySwingWorker mySwingWorker = new MySwingWorker( iSeriesN, dX, dY, sT); mySwingWorker .addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent pcEvt) { if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) { System.out.println("done"); } if ("progress".equals(pcEvt.getPropertyName())) { System.out.println("progress"); } } }); mySwingWorker.execute(); } private class MySwingWorker extends SwingWorker { private double [] dX ; private double [] dY ; private String title; private int iSeriesN; private MySwingWorker(int iSeriesN, double [] ix, double[] iy, String st){ dX = ix.clone(); dY = iy.clone(); title= st; this.iSeriesN = iSeriesN; xySeriesCollection.removeAllSeries(); System.out.println("xySeriesCollection.removeAllSeries();"); } @Override public Void doInBackground() throws IOException { // chartPanel.getChart().removeChangeListener((ChartChangeListener) chartPanel); xySeries[iSeriesN].clear(); for (int i = 0; i < dX.length; i++) { xySeries[iSeriesN].add(dX[i], dY[i]); } for (int i = 0; i < xySeries.length; i++) { setProgress(i * (100 / xySeries.length)); publish(Double.valueOf(i)); try { Thread.sleep(10); } catch (InterruptedException e) { } // simulate latency } return null; } @Override protected void process(List chunks) { for (double d : chunks) { xySeriesCollection.addSeries(xySeries[(int) d]); } } @Override protected void done() { try { // chartPanel.getChart().addChangeListener((ChartChangeListener) chartPanel); xySeries[iSeriesN].setKey(title); } catch (Exception ignore) { } } } public XYSeries addXY(final int iSeriesN, final double [] dX, final double [] dY){ XYSeries series = new XYSeries("Plot "); for (int i = 0; i < dX.length; i++) { series.add(dX[i], dY[i]); } return series; } public static void main(String args[]) { EventQueue.invokeLater(new Runnable() { @Override public void run() { FastChart2 [] demo = new FastChart2[2]; for (int i = 0; i < demo.length; i++) { demo[i] = new FastChart2("Figure "+i); demo[i].multiPlot(); } } }); } } 

我知道我使用swingworker的方式是错误的! 我不知道如何解决它

在开始之前,我有一些提示:

  • 摆脱数组:你有几个,你会发现它们只会把事情弄得乱七八糟,因为你需要索引和循环来处理它们,而且很容易犯错误。 我特别删除了这个:

    private XYSeries [] xySeries; //XYSeriesCollection is intended to keep a series list, so...

  • 如果您不添加任何function,请不要让您的类从JFrame (或任何Swing组件)扩展。 您只需使用变量即可。

  • 除了需要修复SwingWorker实现之外,使用调用此SwingWorker的新Thread更令人不安。 摆脱它(它是不需要的)。

  • 正如@trahsgod在这篇评论中指出的那样, XYSeriesCollection是图表的模型,所以关键是它正在使用它。

说完这个,关于你的SwingWorker实现,它应该是这样的:

 SwingWorker worker = new SwingWorker() { @Override protected Void doInBackground() throws Exception { /* * This part is extracted from your multiPlot() method * I've just reduced the scale factor and get rid of double arrays */ int numberOfElements = 100; // this is the number of elementes in X axis for(int y = 0; y < 12; y++) { // we want 12 series XYSeries series = new XYSeries("Plot " + y); for (int x = 0; x < numberOfElements; x++) { series.add(x, y*10); //add x,y point } publish(series); Thread.sleep(100);// just for animation purpose } return null; } @Override protected void process(List chunks) { for(XYSeries series : chunks){ /* * Add the series to the "model" here. * It will notify the "view" data has been changed and this last one will be updated * It's important make this call here to ensure the "view" is updated in the EDT. */ xySeriesCollection.addSeries(series); } } }; 

工作实例

以下是基于您的工作的完整工作示例,您可以将其作为起点。 希望它有用:)

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Ellipse2D; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.jfree.chart.*; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.util.ShapeUtilities; public class FreeChartDemo { XYSeriesCollection xySeriesCollection; String title; public FreeChartDemo(String title){ this.title = title; } public void initGUI(){ JButton clearChart = new JButton("Clear chart"); clearChart.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { xySeriesCollection.removeAllSeries(); } }); JButton fillChart = new JButton("Fill chart") ; fillChart.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { xySeriesCollection.removeAllSeries(); fillChart(); } }); JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); controlPanel.add(clearChart); controlPanel.add(fillChart); JPanel content = new JPanel(new BorderLayout(5, 5)); content.add(getFreeChartPanel(), BorderLayout.CENTER); //add the ChartPanel here content.add(controlPanel, BorderLayout.SOUTH); JFrame frame = new JFrame("JFreeChart demo"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.getContentPane().add(content); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } private JPanel getFreeChartPanel(){ xySeriesCollection = new XYSeriesCollection(); JFreeChart chart = ChartFactory.createScatterPlot(title, "X axis", "Y axis", xySeriesCollection, PlotOrientation.VERTICAL, true, true, false); XYPlot plot = chart.getXYPlot(); plot.setDomainCrosshairVisible(true); plot.setRangeCrosshairVisible(true); XYItemRenderer renderer = plot.getRenderer(); renderer.setSeriesPaint(0, Color.magenta); renderer.setSeriesPaint(1, Color.green); renderer.setSeriesPaint(2, Color.blue); renderer.setSeriesPaint(4, Color.black); renderer.setSeriesPaint(3, Color.yellow); Shape cross = ShapeUtilities.createDiagonalCross(3, 0); for (int i = 0; i <= 3; i++) { renderer.setSeriesShape(0+i, new Rectangle(-1, -1, 2, 2)); renderer.setSeriesShape(4+i, new Ellipse2D.Float(-2F, -2F, 5F, 5F)); renderer.setSeriesShape(8+i, cross); } NumberAxis domain = (NumberAxis) plot.getDomainAxis(); domain.setRange(0,100); NumberAxis range = (NumberAxis) plot.getRangeAxis(); range.setRange(0,120); return new ChartPanel(chart); } private void fillChart() { SwingWorker worker = new SwingWorker() { @Override protected Void doInBackground() throws Exception { int numberOfElements = 1000; for(int y = 0; y < 12; y++) { XYSeries series = new XYSeries("Plot " + y); for (int x = 0; x < numberOfElements; x++) { series.add(x, y*10); //add x,y point } publish(series); Thread.sleep(100);// just for animation purpose } return null; } @Override protected void process(List chunks) { for(XYSeries series : chunks){ xySeriesCollection.addSeries(series); } } }; worker.execute(); } public static void main(String args[]) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new FreeChartDemo("JFreeChart #1").initGUI(); new FreeChartDemo("JFreeChart #2").initGUI(); } }); } } 

你正在做同样的事情 – 从后台线程调用Swing。

在这里你在multiPlot中创建一个新线程,然后从该线程调用Swing Timer – 不要这样做 – 只应在Swing事件调度线程(或EDT)上启动Swing Timer。 您是否尝试过使用SwingWorker? 如果是这样,你的结果是什么?

并且您似乎正在使用延迟为0的Swing Timer,然后立即停止它。 如果是这样,那有点奇怪,并建议你根本不应该使用计时器。