Adding Chartpanel to Jtabbedpane Using JPAnel

Adding ChartPanel to JTabbedPane using JPanel

As shown in How to Use Tabbed Panes, you can add components to a tabbed pane. ChartPanel, a subclass of JPanel, is such a component. In addition to these examples, you can use the example below to experiment with other features.

As you are new, limit using the NetBeans GUI editor, implied in your question, but continue to use the NetBeans IDE.

tabbed charts

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
* @see https://stackoverflow.com/a/15715096/230513
* @see https://stackoverflow.com/a/11949899/230513
*/
public class TabChart {

private static final int N = 128;
private static final Random random = new Random();
private int n = 1;

private void display() {
JFrame f = new JFrame("TabChart");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTabbedPane jtp = new JTabbedPane();
jtp.add(String.valueOf(n), createPane());
f.add(jtp, BorderLayout.CENTER);
JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
p.add(new JButton(new AbstractAction("Add") {
@Override
public void actionPerformed(ActionEvent e) {
jtp.add(String.valueOf(++n), createPane());
jtp.setSelectedIndex(n - 1);
}
}));
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}

private ChartPanel createPane() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(N) + N / 2; i++) {
series.add(i, random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
new Timer(1000, new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
series.add(series.getItemCount(), random.nextGaussian());
}
}).start();
JFreeChart chart = ChartFactory.createXYLineChart("Test", "Domain",
"Range", dataset, PlotOrientation.VERTICAL, false, false, false);
return new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(480, 240);
}
};
}

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

Adding ChartPanel to CardLayout

Using this example, it's clear that a ChartPanel works correctly in a CardLayout. The example below overrides getPreferredSize(), as shown here, to establish an initial size for the ChartPanel. The use of GridLayout on each card allows the chart to fill the panel as the enclosing frame is resized.

image

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;

/**
* @see https://stackoverflow.com/a/36392696/230513
* @see https://stackoverflow.com/a/36243395/230513
*/
public class CardPanel extends JPanel {

private static final Random r = new Random();
private static final JPanel cards = new JPanel(new CardLayout());
private final String name;

public CardPanel(String name) {
super(new GridLayout());
this.name = name;
DefaultPieDataset pieDataset = new DefaultPieDataset();
pieDataset.setValue("One", r.nextInt(10) + 10);
pieDataset.setValue("Two", r.nextInt(20) + 10);
pieDataset.setValue("Three", r.nextInt(30) + 10);
JFreeChart chart = ChartFactory.createPieChart3D(
"3D Pie Chart", pieDataset, true, true, true);
chart.setTitle(name);
this.add(new ChartPanel(chart) {

@Override
public Dimension getPreferredSize() {
return new Dimension(500, (int)(500 * 0.62));
}
});
}

@Override
public String toString() {
return name;
}

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

@Override
public void run() {
create();
}
});
}

private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 1; i < 9; i++) {
CardPanel p = new CardPanel("Chart " + String.valueOf(i));
cards.add(p, p.toString());
}
JPanel control = new JPanel();
control.add(new JButton(new AbstractAction("\u22b2Prev") {

@Override
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) cards.getLayout();
cl.previous(cards);
}
}));
control.add(new JButton(new AbstractAction("Next\u22b3") {

@Override
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) cards.getLayout();
cl.next(cards);
}
}));
f.add(cards, BorderLayout.CENTER);
f.add(control, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}

Adding new Tab with JTabbedPane through event

In the future please post an SSCCE instead of copy/pasting some classes.

Here's an SSCCE of your MainScreen, with the non-essentials stripped out, and a main method added:

import java.awt.*;
import javax.swing.*;

public class MainScreen extends JFrame
{
JTabbedPane tabbedPane = new JTabbedPane();
final JPanel entrance = new JPanel();

public MainScreen()
{
tabbedPane.addTab("Entrance", entrance);
add(tabbedPane, BorderLayout.CENTER);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new MainScreen();
frame.setSize(300, 200);
frame.setVisible(true);
}
});
}
}

... and here's an SSCCE for QueryScreen:

import java.awt.*;
import javax.swing.*;

public class QueryScreen extends MainScreen
{
final JPanel queryList = new JPanel();

public QueryScreen()
{
tabbedPane.addTab("Query List", queryList);
//add( tabbedPane, BorderLayout.CENTER ); /* not needed */
}

public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new QueryScreen();
frame.setSize(300, 200);
frame.setVisible(true);
}
});
}
}

As you can see, this works, and for the most part, all I did was remove unnecessary code and added a main to each.

If you're still having problems, please update your question with an SSCCE and post the specific problem you're having.

JPanel added but not displayed in time

An explanation of why is this happening would be great.

You may get some insight from the variation below. Note

  • Swing GUI objects should be constructed and manipulated only on the event dispatch thread (EDT) for the reason suggested here.

  • The EDT continues to process events, as shown in the example, even while user interaction is limited to the modal dialog.

  • Invoking repaint() should not be required when using ChartPanel.

  • Prefer CardLayout or JTabbedPane over manual container manipulation.

  • Rather than invoking setPreferredSize(), override getPreferredSize(), as discussed here.

Addendum: You have removed the two lines … that are showing the problem.

ChartRenderingInfo is dynamic data that doesn't exist until the chart has been rendered. The modal dialog handles events while the chart is updated in the background; without it, you can schedule your method by wrapping it in a Runnable suitable for invokeLater():

EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
myPanel.methodCalledOnceDisplayed();
}
});

A better scheme is to access the ChartRenderingInfo in listeners where you know the data is valid, i.e. listeners implemented by ChartPanel.

image

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;

/**
* @see https://stackoverflow.com/a/14894894/230513
*/
public class Test extends JFrame {

private JPanel panel;

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

@Override
public void run() {
Test frame = new Test();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public Test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyJPanel myPanel = new MyJPanel();
panel = new JPanel() {

@Override
public Dimension getPreferredSize() {
return myPanel.getPreferredSize();
}
};
panel.setBorder(new EmptyBorder(5, 5, 5, 5));
panel.setLayout(new BorderLayout());
add(panel);

myPanel.start();
JButton clickme = new JButton("Click me");
clickme.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent arg0) {
panel.removeAll();
panel.add(myPanel, BorderLayout.CENTER);
validate();
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
myPanel.methodCalledOnceDisplayed();
}
});
}
});
panel.add(clickme, BorderLayout.NORTH);
JPanel example = new JPanel();
example.add(new JLabel("Example JPanel"));
panel.add(example, BorderLayout.CENTER);
}

private static class MyJPanel extends JPanel {

private static final Random r = new Random();
private ChartPanel chartPanel;
private JFreeChart chart;
private XYPlot subplotTop;
private XYPlot subplotBottom;
private CombinedDomainXYPlot plot;
private Timer timer;
private Day now = new Day(new Date());

public MyJPanel() {
this.add(new JLabel("Chart panel"));
createCombinedChart();
chartPanel = new ChartPanel(chart);
this.add(chartPanel);
timer = new Timer(1000, new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
update(subplotTop);
update(subplotBottom);
}
});
timer.start();
}

public void start() {
timer.start();
}

private void update(XYPlot plot) {
TimeSeriesCollection t = (TimeSeriesCollection) plot.getDataset();
for (int i = 0; i < t.getSeriesCount(); i++) {
TimeSeries s = t.getSeries(i);
s.add(now, Math.abs(r.nextGaussian()));
now = (Day) now.next();
}
}

private void createCombinedChart() {
plot = new CombinedDomainXYPlot();
plot.setGap(30);
createSubplots();
plot.add(subplotTop, 4);
plot.add(subplotBottom, 1);
plot.setOrientation(PlotOrientation.VERTICAL);
chart = new JFreeChart("Title",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
plot.setDomainAxis(new DateAxis("Domain"));
}

private void createSubplots() {
subplotTop = new XYPlot();
subplotBottom = new XYPlot();
subplotTop.setDataset(emptyDataset("Set 1"));
subplotTop.setRenderer(new XYLineAndShapeRenderer());
subplotTop.setRangeAxis(new NumberAxis("Range"));
subplotBottom.setDataset(emptyDataset("Set 2"));
subplotBottom.setRenderer(new XYLineAndShapeRenderer());
subplotBottom.setRangeAxis(new NumberAxis("Range"));
}

private XYDataset emptyDataset(String title) {
TimeSeriesCollection tsc = new TimeSeriesCollection();
TimeSeries ts = new TimeSeries(title);
tsc.addSeries(ts);
return tsc;
}

public void methodCalledOnceDisplayed() {
PlotRenderingInfo plotInfo =
this.chartPanel.getChartRenderingInfo().getPlotInfo();
for (int i = 0; i < plotInfo.getSubplotCount(); i++) {
System.out.println(plotInfo.getSubplotInfo(i).getDataArea());
}
JOptionPane.showMessageDialog(null, "Magic!");
}
}
}

Addendum: One additional iteration to illustrate ChartMouseListener and clean up a few loose ends.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;

/**
* @see https://stackoverflow.com/a/14894894/230513
*/
public class Test {

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

@Override
public void run() {
Test t = new Test();
}
});
}

public Test() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyJPanel myPanel = new MyJPanel();
f.add(myPanel, BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
myPanel.start();
}

private static class MyJPanel extends JPanel {

private static final Random r = new Random();
private ChartPanel chartPanel;
private JFreeChart chart;
private XYPlot subplotTop;
private XYPlot subplotBottom;
private CombinedDomainXYPlot plot;
private Timer timer;
private Day now = new Day(new Date());

public MyJPanel() {
createCombinedChart();
chartPanel = new ChartPanel(chart);
this.add(chartPanel);
timer = new Timer(1000, new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
update(subplotTop);
update(subplotBottom);
now = (Day) now.next();
}
});
chartPanel.addChartMouseListener(new ChartMouseListener() {

@Override
public void chartMouseClicked(ChartMouseEvent e) {
final ChartEntity entity = e.getEntity();
System.out.println(entity + " " + entity.getArea());
}

@Override
public void chartMouseMoved(ChartMouseEvent e) {
}
});
}

public void start() {
timer.start();
}

private void update(XYPlot plot) {
TimeSeriesCollection t = (TimeSeriesCollection) plot.getDataset();
for (int i = 0; i < t.getSeriesCount(); i++) {
TimeSeries s = t.getSeries(i);
s.add(now, Math.abs(r.nextGaussian()));
}
}

private void createCombinedChart() {
plot = new CombinedDomainXYPlot();
createSubplots();
plot.add(subplotTop, 4);
plot.add(subplotBottom, 1);
plot.setOrientation(PlotOrientation.VERTICAL);
chart = new JFreeChart("Title",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
plot.setDomainAxis(new DateAxis("Domain"));
}

private void createSubplots() {
subplotTop = new XYPlot();
subplotBottom = new XYPlot();
subplotTop.setDataset(emptyDataset("Set 1"));
subplotTop.setRenderer(new XYLineAndShapeRenderer());
subplotTop.setRangeAxis(new NumberAxis("Range"));
subplotBottom.setDataset(emptyDataset("Set 2"));
subplotBottom.setRenderer(new XYLineAndShapeRenderer());
subplotBottom.setRangeAxis(new NumberAxis("Range"));
}

private XYDataset emptyDataset(String title) {
TimeSeriesCollection tsc = new TimeSeriesCollection();
TimeSeries ts = new TimeSeries(title);
tsc.addSeries(ts);
return tsc;
}
}
}

How can I redirect my jfreecharts into the tabs?

You have a single, static instance of TimeSeries, ts, to which you add all your data. You then use that single instance to create each chart panel. As a result, the charts all display the same data. Instead, create a single instance of TimeSeriesCollection to which you add a TimeSeries for each zone. You can use the zone name as the series key and later retrieve each series by name as you construct each chart panel.

As an aside, consider coding to the collection interface, for example

Map<String, Map<Integer, List<Integer>>> zoneMap = new TreeMap<>();

Addendum: Do I create a TimeSeries for each zone?

Yes. Given the following declarations,

private static final String titles[] = {
"Zone A", "Zone B", "Zone C", "Zone S", "Zone SH", "Zone W"};
private final TimeSeriesCollection all = new TimeSeriesCollection();

You can add an empty series to the collection for each zone and use the zone name as the key of each TimeSeries. When encountering a zone name in the CSV file, get the corresponding TimeSeries by name and add its data.

private void createInduction() {
for (String s : titles) {
all.addSeries(new TimeSeries(s));
}
// while parsing the CSV file
String zone = …;
TimeSeries ts = all.getSeries(zone);
// add data to this zone's series
}

Later, use the zone name to get the dataset needed to construct the chart.

private ChartPanel createPane(String title) {
TimeSeriesCollection dataset = new TimeSeriesCollection(all.getSeries(title));
JFreeChart chart = ChartFactory.createXYBarChart(…. dataset. …);
// decorate chart
return new ChartPanel(chart);
}

Finally, use the zone name to create each pane.

private void display() {

JTabbedPane jtp = new JTabbedPane();
for (String s : titles) {
jtp.add(createPane(s));
}

}

JTabbedPane Auto-Load components

In your ListSelectionListener, create and add() your new panel. In this complete example, a new panel in added in the Add button's ActionListener. Your createPane() method would need the parameters required to fill out a single address card.



Related Topics



Leave a reply



Submit