JFreeChart MeterPlot
Asked Answered
H

2

2

I'm currently doing Agent project in java. At some point I need to show a meter for eg: battery level. I've got 5 agents in my program, each agent creates it's own meter plot with name on it, but somehow they are not updating the dataset. OR they are updating the dataset just that it isnt show on the meterplot. Any idea ?

Following is my code : car.java

{
    private CarMeter meter;
    meter = new CarMeter(getLocalName());
    meter.update(currentBatteryCharge);
}

meterplot.java

public class CarMeter extends ApplicationFrame {

 private static DefaultValueDataset dataset1;

public CarMeter(String s) {
    super(s);
    JPanel panel = createPanel();
    panel.setPreferredSize(new Dimension(500, 350));
    setContentPane(panel);
    pack();
    setVisible(true);
}

public CarMeter() {
    super("s");
    JPanel panel = createPanel();
    panel.setPreferredSize(new Dimension(500, 350));
    setContentPane(panel);
    pack();
    setVisible(true);
}

private static JFreeChart createChart(ValueDataset valuedataset) {
    MeterPlot meterplot = new MeterPlot(valuedataset);
  //set minimum and maximum value
    meterplot.setRange(new Range(0.0D, 100000D));

    meterplot.addInterval(new MeterInterval("Battery LOW", new Range(0.0D, 10000D), 
            Color.red, new BasicStroke(2.0F), new Color(255, 0, 0, 128)));

    meterplot.addInterval(new MeterInterval("Moderate", new Range(10001D, 90000D), 
            Color.yellow, new BasicStroke(2.0F), new Color(255, 255, 0, 64)));

    meterplot.addInterval(new MeterInterval("Battery FULL", new Range(90001D, 100000D),
            Color.green, new BasicStroke(2.0F), new Color(0, 255, 0, 64)));

    meterplot.setNeedlePaint(Color.darkGray);
    meterplot.setDialBackgroundPaint(Color.white);
    meterplot.setDialOutlinePaint(Color.black);
    meterplot.setDialShape(DialShape.CHORD);
    meterplot.setMeterAngle(180);
    meterplot.setTickLabelsVisible(true);
    meterplot.setTickLabelFont(new Font("Arial", 1, 12));
    meterplot.setTickLabelPaint(Color.black);
    meterplot.setTickSize(5D);
    meterplot.setTickPaint(Color.gray);
    meterplot.setValuePaint(Color.black);
    meterplot.setValueFont(new Font("Arial", 1, 14));
    JFreeChart jfreechart = new JFreeChart("Battery Level",
            JFreeChart.DEFAULT_TITLE_FONT, meterplot, true);
    return jfreechart;
}

public static JPanel createPanel() {
    dataset1 = new DefaultValueDataset(0);
    JFreeChart chart = createChart(dataset1);
    ChartPanel chartpanel = new ChartPanel(chart);
    return chartpanel;
}

public void update(int data){
dataset1.setValue(data);
System.out.println(""+dataset1 +" " +data);
}
Haug answered 7/11, 2013 at 9:17 Comment(2)
I've tried your code, it works. update method work for me. What the problem for you with it?Scupper
I've a initialiser which create 5 car.java. Each of them have their own meterplot. name : Car 1 , Car 2.. etc. Suppose 5 plots should be updating according to ticker. But it does not update all plot. It only update ie : Car 2 meter plot. The rest remain 0.Haug
H
4

As noted by @alex2410, your code works as shown below. As noted in an answer cited by @Outlaw, the plot (view) listens to the dataset (model). Some notes,

  • Don't repeat code in constructors; let one invoke another.

  • Don't use setPreferredSize() when you really mean to override getPreferredSize().

  • Don't use a static member to reference the model in a reusable view class.

  • Don't invoke public methods in constructors.

  • Do use contiguous ranges to avoid visual artifact in labels.

image

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.data.Range;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.data.general.ValueDataset;
import org.jfree.ui.ApplicationFrame;

public class CarMeter extends ApplicationFrame {

    private DefaultValueDataset dataset;
    private int value = 50000;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new CarMeter();
            }
        });
    }

    public CarMeter(String s) {
        super(s);
        JPanel panel = createPanel();
        setContentPane(panel);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        Timer t = new Timer(250, new ActionListener() {
            Random r = new Random();

            @Override
            public void actionPerformed(ActionEvent e) {
                value -= (int) (Math.abs(100 * r.nextGaussian()));
                update(value);
            }
        });
        t.start();
    }

    public CarMeter() {
        this("Test");
    }

    private JFreeChart createChart(ValueDataset valuedataset) {
        MeterPlot meterplot = new MeterPlot(valuedataset);
        meterplot.setRange(new Range(0.0D, 100000D));
        meterplot.addInterval(new MeterInterval("Battery LOW", new Range(0.0D, 10000D),
            Color.red, new BasicStroke(2.0F), new Color(255, 0, 0, 128)));
        meterplot.addInterval(new MeterInterval("Moderate", new Range(10000D, 90000D),
            Color.yellow, new BasicStroke(2.0F), new Color(255, 255, 0, 64)));
        meterplot.addInterval(new MeterInterval("Battery FULL", new Range(90000D, 100000D),
            Color.green, new BasicStroke(2.0F), new Color(0, 255, 0, 64)));

        meterplot.setNeedlePaint(Color.darkGray);
        meterplot.setDialBackgroundPaint(Color.white);
        meterplot.setDialOutlinePaint(Color.black);
        meterplot.setDialShape(DialShape.CHORD);
        meterplot.setMeterAngle(180);
        meterplot.setTickLabelsVisible(true);
        meterplot.setTickLabelFont(new Font("Arial", 1, 14));
        meterplot.setTickLabelPaint(Color.black);
        meterplot.setTickSize(5D);
        meterplot.setTickPaint(Color.gray);
        meterplot.setValuePaint(Color.black);
        meterplot.setValueFont(new Font("Arial", 1, 14));
        JFreeChart jfreechart = new JFreeChart("Battery Level",
            JFreeChart.DEFAULT_TITLE_FONT, meterplot, true);
        return jfreechart;
    }

    private JPanel createPanel() {
        dataset = new DefaultValueDataset(value);
        JFreeChart chart = createChart(dataset);
        ChartPanel chartpanel = new ChartPanel(chart) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(640, 480);
            }
        };
        return chartpanel;
    }

    public void update(int data) {
        dataset.setValue(data);

    }
}
Houri answered 7/11, 2013 at 10:41 Comment(3)
Hi, Thanks for your advise. Here is something more obvious. If i add another new CarMeter in main. And both start updating. 2 meter plot will show but only 1 will get updated. public static void main(String args[]) { CarMeter boo = new CarMeter("boo"); CarMeter foo = new CarMeter("foo"); for(int i = 0 ; i < 100 ; i ++){ foo.update(1000+i); boo.update(5000+i); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}Haug
I'm wary of a static model or more than one frame; please edit your question to include an sscce that shows your current approach.Houri
I have tried example of @trashgod, modified it, i add 5 charts to one JFrame and update them with help of SwingTimer it works fine. Look at this example, it's answer for your question. If you don't think so, post your code, where you create ALL your meters and try to update them.Scupper
T
1

Think this is a duplicate to Jfreechart - Refresh a chart according to changing data

You need to redraw the diagram in some way, the update method will only set the datavalue but leave the Chart itself unchanged.

For a quick and dirty fix without further looking into it i would suggest to call the createChart method again (inside your update methode) and update the chart object.

Just to verify if that would solve the problem. I suggest you reading into the GOF observer pattern, it is a nice way to seperate GUI from data and update the GUI when needed http://en.wikipedia.org/wiki/Observer_pattern.

Trifocal answered 7/11, 2013 at 9:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.