2016-06-29 5 views
0

Ich zeichne derzeit eine JFreeChart, die ich mit verschiedenen "Bildwiederholfrequenzen" drucken möchte. Im Moment kann ich es mit "One Shot" drucken, aber ich konnte es nicht dynamisch drucken. Die Bildwiederholrate habe ich als int Wert in meinem Code gespeichert.Update eine XY-Linie JFreeChart dynamisch mit verschiedenen Aktualisierungsraten

Bevor ich drucke, mache ich alle Berechnungen und drucke sie dann aus. Was ich jetzt versuche, ist Druck während der Berechnung. Sobald ich den Wert eines Punktes erhalten habe, drucke es und so weiter.

Meine Berechnung Code lautet wie folgt:

XYLineChart_AWT chartTemp = new XYLineChart_AWT(); 
int refreshRate = getRefreshRate(); 
for (int i = 0; i<MaxValue;i++) { 
    //calculate values of Array1, Array2 and Array3 
    chart1.setChart(chartTemp.runSimGraph("Title", "XLabel", "YLabel",true, new double[][]{Array1,Array2,Array3})); 
} 

Dies ist jedoch nur, dass druckt die JFreeChart am Ende des for -loop (versuchte es mit Thread.sleep() -Methode vor Ablauf der jeweiligen for Iteration).

Wie kann ich den Graphen dynamisch drucken? Muss ich den Datensatz aktualisieren, während ich die Werte berechne? Wenn ja, wie kann ich das tun?

EDIT: Ich habe ein kleines überprüfbares Beispiel erstellt, was ich erfüllen möchte. Wenn ich den Knopf drücke, erscheint das Diagramm nicht, wenn die Berechnungen gemacht werden, es erscheint nur, wenn es fertig ist. Ich möchte, dass es Punkt für Punkt nach der Berechnung angezeigt wird. Und ja, das Aufrufen von setChart() bei jeder Iteration ist sehr uneffizient.

Code: Test1.java

package cenas; 

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTabbedPane; 

import net.miginfocom.swing.MigLayout; 

public class Test1 extends JFrame 
{ 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 
    /** 
    * 
    */ 
    private JTabbedPane tabbedBackground; 



    /** 
    * Launch the application. 
    */ 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        Test2 secondFrame = new Test2(); 
        Test1 mainFrame = new Test1(secondFrame); 
        mainFrame.setVisible(true); 
        secondFrame.setVisible(true); 
        secondFrame.setLocationRelativeTo(null); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     // given some values of w & h 
     return new Dimension(1000, 650); 
    } 

    /** 
    * Create the frame. 
    */ 
    public Test1(Test2 secondFrame) { 

     this.setLocationByPlatform(true); 
     setTitle("IMESS Simulator"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setMinimumSize(new Dimension(1000, 650)); 


     tabbedBackground = new JTabbedPane(JTabbedPane.TOP); 
     setContentPane(tabbedBackground); 
     initComponentsandRunSimulator(secondFrame); 
     pack(); 
     //setResizable(false); 

    } 

    private void initComponentsandRunSimulator(Test2 frame2) { 


     JPanel panel1 = new JPanel(); 
     tabbedBackground.addTab("Strategy and Results", null, panel1, null); 
     tabbedBackground.setEnabledAt(0,true); 
     panel1.setLayout(new MigLayout("", "[400.00px,grow]20[300px,grow]20[300.00px,grow]", "[40px,grow 20][][][][][100px,grow]20[20px]20[250.00px,grow]")); 


     JButton myButton = new JButton("Button - Press me"); 
     myButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       frame2.setComponentsLists(100); 
      } 
     }); 

     //Add Simulation Panel to the layout 
     panel1.add(myButton, "cell 1 1 2 5,grow"); 
    } 

} 

Test2.java

package cenas; 

import java.awt.Dimension; 
import java.awt.EventQueue; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTabbedPane; 

import org.jfree.chart.ChartPanel; 


import net.miginfocom.swing.MigLayout; 

public class Test2 extends JFrame{ 


    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 
    private JTabbedPane tabbedBackground2; 
    private ChartPanel chart1 = new ChartPanel (null); 
    private int value; 



    @Override 
    public Dimension getPreferredSize() { 
     // given some values of w & h 
     return new Dimension(1000, 650); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        Test2 frame = new Test2(); 
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public void setComponentsLists(int refreshRate) { 
     this.value=refreshRate; 
     System.out.println("ola"); 
     simulateValues(refreshRate); 
    } 

    public Test2() { 
     setTitle("IMESS Simulator - Decision System"); 
     setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 
     setLocationRelativeTo(null); 
     setMinimumSize(new Dimension(1000, 650)); 

     tabbedBackground2 = new JTabbedPane(JTabbedPane.TOP); 
     setContentPane(tabbedBackground2); 
     initComponents(); 
     pack(); 
    } 

private void initComponents() { 

     // Panel 
     JPanel panelSimulation = new JPanel(); 
     tabbedBackground2.addTab("Strategy and Results", null, panelSimulation, null); 
     tabbedBackground2.setEnabledAt(0,true); 
     panelSimulation.setLayout(new MigLayout("", "[400.00px,grow]20[300px,grow]20[300.00px,grow]", "[40px,grow 20][][][][][100px,grow]20[20px]20[250.00px,grow]")); 

     chart1.setPopupMenu(null); 
     chart1.setVisible(true); 

     //Add Simulation Panel to the layout 
     panelSimulation.add(chart1, "cell 0 2"); 
    } 

private void simulateValues(int sliderValue) { 



    double[] Array1 = new double[1440]; 
    double[] Array2 = new double[1440]; 
    double[] Array3 = new double[1440]; 
    for(int i = 0; i<1440; i++) { 
     Array1[i]=0; 
     Array2[i]=0; 
     Array3[i]=0; 
    } 

    int peaks = 0; 



    GraphTest chartTemp = new GraphTest(); 


    //Simulation for 24h (1 point per minute) 
    for(int i = 0; i<1440; i++) { 
     //Some calculations 
     if(i!=0) 
      Array1[i]=Array1[i-1]; 

     if (((i>5) && (i<300)) || ((i>400) && (i<700))) 
     { 
      //Increase the energy per minute 
      if((Array1[i]+10)<=50) 
       Array1[i] = Array1[i]+ 10; 

      else { //if we charge at normal rate, it could surpass capacity, so there may be leftovers 
       Array1[i]=27; 

      }  

     } 

     if (peaks==0) { 
      //Check if there is enough energy to supply in the ESS 
      if(Array1[i]>Array2[i]) { 

       Array3[i]=Array2[i]; //usage by the ESS 
       Array2[i]=0; //Visualization purposes - grid does not provide any energy 
       Array1[i]=Array1[i] - Array3[i]; //energy used by ESS 

      } 

     } 

     chart1.setChart(chartTemp.runSimGraph("Title", "xLabel", "yLabel", true, new double[][]{Array1,Array2,Array3})); 
    } 


} 


} 

GraphTest.java

package cenas; 

import java.awt.Color; 
import java.awt.Shape; 
import java.awt.geom.Rectangle2D; 
import org.jfree.chart.JFreeChart; 
import org.jfree.chart.axis.NumberAxis; 
import org.jfree.data.xy.XYDataset; 
import org.jfree.data.xy.XYSeries; 
import org.jfree.chart.plot.XYPlot; 
import org.jfree.chart.ChartFactory; 
import org.jfree.chart.plot.PlotOrientation; 
import org.jfree.data.xy.XYSeriesCollection; 
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; 



public class GraphTest { 


    public JFreeChart runSimGraph(String chartTitle, String xLabel, String yLabel, boolean legend ,double[][] graphValues) { 


     JFreeChart xylineChart = ChartFactory.createXYLineChart(
      chartTitle, 
      xLabel, 
      yLabel, 
      createSimDataset(graphValues), 
      PlotOrientation.VERTICAL, 
      legend, false, false); 
     final XYPlot plot = xylineChart.getXYPlot(); 

     //Axes (Domain - x , Range - y) 
     NumberAxis domain = (NumberAxis) plot.getDomainAxis(); 
     domain.setRange(0,24); 
     plot.setBackgroundPaint(new Color(240, 240, 240)); 
     XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true); 
     //renderer.setBaseLinesVisible(false); // retira as linhas entre os pontos 
     //renderer.setBaseShapesFilled(false); //apaga o centro das shapes 
     //renderer.setBaseShapesVisible(false); //apaga as shapes 
     Shape teste = new Rectangle2D.Double(-(1.2/2), -(1.2/2), 1.2, 1.2); 
     renderer.setSeriesShape(0, teste); 
     renderer.setSeriesPaint(0, Color.RED); 
     //renderer.setSeriesStroke(0, new BasicStroke(1.0f)); 
     renderer.setSeriesShape(1, teste); 
     renderer.setSeriesPaint(1, Color.BLUE); 
     renderer.setSeriesShape(2, teste); 
     renderer.setSeriesPaint(2, Color.GREEN); 
     plot.setRenderer(renderer); 

     return xylineChart; 
    } 

    private XYDataset createSimDataset(double[][] values) { 

     double[] gridAr=values[0]; 
     double[] essAr=values[1]; 
     double[] availableEnergy=values[2]; 

     final XYSeries temp1 = new XYSeries("1"); 
     final XYSeries temp2 = new XYSeries("2"); 
     final XYSeries temp3 = new XYSeries("3"); 


     for (double i = 0; i < 1440; i++) { 
      temp1.add(i/60, gridAr[(int) i]); 
      temp2.add(i/60, essAr[(int)i]); 
      temp3.add(i/60, availableEnergy[(int) i]); 
     } 
     final XYSeriesCollection dataset = new XYSeriesCollection(); 
     dataset.addSeries(temp1); 
     dataset.addSeries(temp2); 
     dataset.addSeries(temp3); 
     return dataset; 
    } 




} 

Vielen Dank im Voraus und sorry für die "langen Pfosten",

Nhekas

+0

'Mein calculattion Code ist als folgt: 'Wo wird dieser 'Berechnungscode' aufgerufen? Mit anderen Worten, in welchem ​​Kontext? Ist das in einem eigenen Thread? Auf der EDT? – copeg

+0

@copeg du hast Recht, es ist keine vollständige Erklärung. Ich habe eine Haupt-Java-Klasse, die ein Jframe mit verschiedenen Komponenten ist. Wenn ich eine bestimmte Taste drücke, beginnen die Berechnungen. Daher wird diese "for" -Schleife innerhalb eines "ActionListener" von Jbutton aufgerufen. – Nhekas

+0

'Diese for-Schleife wird innerhalb einer Schaltfläche aufgerufen. Meinst du das in einem ActionListener der JButton? – copeg

Antwort

2

Swing ist single threaded - Malen und Ereignisse treten im Event-Versand-Thread (EDT) auf. Von Ihrem obigen Kommentar aus wird die von Ihnen gepostete Schleife innerhalb einer ActionListener - die auf dem EDT auftritt, aufgerufen, so dass Änderungen an der Benutzeroberfläche (z. B. Änderungen in Diagrammen) erst dann erfolgen, wenn der EDT frei ist (z. B. irgendwann nach dem Ende der actionPerformed Methode)).

, was ich mit verschiedenen „Bildwiederholraten“ drucken möchten

Wenn Sie das gesamte Diagramm mit einer bestimmten Rate auffrischen wollen, würde ich empfehlen, ein javax.swing.Timer verwenden, aktualisieren Sie das Diagramm wie nötig . Zum Beispiel mit einer Rate von einmal den Timer aus der Action eines JButton abzuzufeuern pro Sekunde:

ActionListener buttonListener = new ActionListener(){ 

    @Override 
    public void actionPerformed(ActionEvent e) { 

     javax.swing.Timer timer = new javax.swing.Timer(1000, new ActionListener(){ 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       //create the arrays 
       chart1.setChart(chartTemp.runSimGraph("Title", "XLabel", "YLabel",true, new double[][]{Array1,Array2,Array3})); 
      } 

     }); 
     timer.start(); 
    } 
}; 
myButton.addActionListener(buttonListener); 

Wenn Sie ein Diagramm mit Punkten aktualisiert werden sollen, wie sie verfügbar sind, sollen Sie a) Durchführung von Berechnungen in einem eigenen Thread und dann b) fügen Sie die Punkte der XYSeries hinzu (auf dem EDT - dies ist im Gegensatz zu den Datensatz jedes Mal neu erstellen).Ein Beispiel, angepasst von Adding points to XYSeries dynamically with JfreeChart:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.util.*; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

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.XYDataset; 
import org.jfree.data.xy.XYSeries; 
import org.jfree.data.xy.XYSeriesCollection; 


public class DynamicPlotAddition extends JFrame { 

    private static final String title = "Dynamic Point Addition"; 
    private final Random rand = new Random(); 
    private XYSeries series = new XYSeries("Added"); 

    public DynamicPlotAddition(String s) { 
     super(s); 
     final ChartPanel chartPanel = createDemoPanel(); 
     this.add(chartPanel, BorderLayout.CENTER); 
     Runnable runner = new Runnable(){ 

      @Override 
      public void run() { 
       int total = 1000; 
       int iter = 0; 
       while (iter++ < total){ 
        SwingUtilities.invokeLater(new Runnable(){ 

         @Override 
         public void run() { 
          series.add(rand.nextGaussian(), rand.nextGaussian()); 
         } 

        }); 

        try{Thread.sleep(100);}catch(Exception e){} 
       } 
      } 

     }; 
     new Thread(runner).start(); 
    } 

    private ChartPanel createDemoPanel() { 
     JFreeChart jfreechart = ChartFactory.createScatterPlot(
      title, "X", "Y", createDataset(), 
      PlotOrientation.VERTICAL, true, true, false); 
     XYPlot xyPlot = (XYPlot) jfreechart.getPlot(); 
     xyPlot.setDomainCrosshairVisible(true); 
     xyPlot.setRangeCrosshairVisible(true); 
     XYItemRenderer renderer = xyPlot.getRenderer(); 
     renderer.setSeriesPaint(0, Color.blue); 
     NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis(); 
     domain.setVerticalTickLabels(true); 
     return new ChartPanel(jfreechart); 
    } 

    private XYDataset createDataset() { 
     XYSeriesCollection xySeriesCollection = new XYSeriesCollection(); 
     xySeriesCollection.addSeries(series); 
     return xySeriesCollection; 
    } 

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

      @Override 
      public void run() { 
       DynamicPlotAddition demo = new DynamicPlotAddition(title); 
       demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       demo.pack(); 
       demo.setLocationRelativeTo(null); 
       demo.setVisible(true); 
      } 
     }); 
    } 
} 

Im Beispiel geschrieben, machen Sie den Anruf simulateValues von einem neuen Thread, und wie jeder Punkt Paar erzeugt wird, um die entsprechende Serie aktualisiert

+0

Die Updates für das Diagramm sollten auf der EWT durchgeführt werden, also verwenden Sie entweder einen SwingWorker anstelle von Timer, oder wickeln Sie den Aufruf von setChart() in eine SwingUtilities.invokeLater() – FredK

+0

@copeg Danke, aber diese Lösung hat nicht funktioniert, weil Wenn ich diesen Timer in die Schleife einfüge, führt er nur die Methode actionPerformed aus, nachdem sie beendet wurde. Und ich möchte für jede Iteration das Diagramm aktualisieren. – Nhekas

+0

@FredK Es ist ein Swing-Timer .... Aus [Wie zu verwenden ...] (https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) 'Swing-Timer-Aufgabe wird in durchgeführt Der Event-Versand-Thread " – copeg