Reputation: 61
I'm currently drawing a JFreeChart
that I want to print with different "refresh rates". At the moment, I can print it with "one shot", however I haven't been able to print it dinamically. The refresh rate I have it as an int
value saved in my code.
Before printing, I make all of the calculations and then print it. What I am trying to do now is print while calculating. As soon as I get the value of one point, print it, and so on.
My calculation code is as follows:
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}));
}
However, this does only prints the JFreeChart
at the end of the for
-loop (tried it with Thread.sleep() method before the ending of each for
iteration).
How may I be able to print the graph dinamically? Do I need to update the dataset as I calculate the values? If so, how can I do that?
EDIT: I've created a small verifiable example of what I want to fulfill. If I press the button, instead of the chart showing up as the calculations are made, it just shows up when it is finished. I want a way for it to show up point by point after its calculation. And yes, calling setChart() every iteration is wildly unefficient.
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;
}
}
Thanks in advance and sorry for the "long post",
Nhekas
Upvotes: 0
Views: 1269
Reputation: 8348
Swing is single threaded - painting and events occur on the Event dispatch thread (EDT). From your comment above, the loop you posted is called within an ActionListener
- which occurs on the EDT, so changes to the UI (eg changes in charts) will not occur until the EDT is free to repaint (eg sometime after the actionPerformed
method ends).
what I want to print with different "refresh rates"
If you want to refresh the entire chart at a given rate, I would recommend using a javax.swing.Timer
, updating the chart as necessary. For example, to fire the timer from the ActionListener of a JButton at a rate of once per second:
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);
If you want to refresh a chart with points as they become available, consider a) performing your calculations in its own thread and then b) add the points to the XYSeries (on the EDT - this is as opposed to recreating the dataset every time). An example, adapted from 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);
}
});
}
}
In the example posted, you make the call to simulateValues
from a new thread, and as each point pair is generated update the appropriate series
Upvotes: 2