JFreechart 程序 运行,但 window 未显示
JFreechart program running, but window not displayed
我 运行 代码基于 here 在 OS X 上使用 Eclipse 所示的示例,我正在使用 JFreeChart 和 JCommon 库。
正如我在标题中所说,该程序 运行 但不显示任何内容。
作为检查,我尝试使用 printData() 方法打印数据,它运行良好。
它正确地从雅虎 csv 文件中获取数据。
我什至尝试使用一小部分数据(20 行),但它一直不显示。
问题可能在于显示 JFrame window。
我插入的试图修复它的代码位于 //BEGIN 和 //END 注释之间。
等待回复,
谢谢。
SEMI-SOLVED:
代码没问题,问题出在JFreeChart库上。
我试图在另一个以前工作的 JFrame class 中 "Build Path> Add my JFreeChart lib"。
当我插入 JFreeChart 库时,它会抑制 window 显示。即使我什么都不进口;只需将库添加到构建路径即可。
作为默认系统库,我使用 "JRE System Library [JavaSE-1.7]"。
代码:
package marketAnalyzer;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.MovingAverage;
import org.jfree.data.xy.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.text.*;
import java.util.*;
import java.util.List;
public class CandlestickDemo extends JFrame {
public CandlestickDemo(String stockSymbol) {
super("CandlestickDemo");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DateAxis domainAxis = new DateAxis("Date");
NumberAxis rangeAxis = new NumberAxis("Price");
CandlestickRenderer renderer = new CandlestickRenderer();
XYDataset dataset = getDataSet(stockSymbol);
XYPlot mainPlot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
final long ONE_DAY = 24 * 60 * 60 * 1000;
XYLineAndShapeRenderer maRenderer = new XYLineAndShapeRenderer(true, false);
XYDataset maSataset = MovingAverage.createMovingAverage(dataset, "MA", 30 * ONE_DAY, 0);
mainPlot.setRenderer(1, maRenderer);
mainPlot.setDataset (1, maSataset);
//Do some setting up, see the API Doc
renderer.setSeriesPaint(0, Color.BLACK);
renderer.setDrawVolume(false);
rangeAxis.setAutoRangeIncludesZero(false);
domainAxis.setTimeline( SegmentedTimeline.newMondayThroughFridayTimeline() );
//Now create the chart and chart panel
JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(600, 300));
this.add(chartPanel);
this.pack();
//BEGIN
//TRYING TO DISPLAY THE WINDOW
chartPanel.setLayout(new java.awt.BorderLayout());
chartPanel.validate();
this.setLayout(new java.awt.BorderLayout());
this.validate();
chartPanel.repaint();
this.repaint();
//END
}
protected AbstractXYDataset getDataSet(String stockSymbol) {
//This is the dataset we are going to create
DefaultOHLCDataset result = null;
//This is the data needed for the dataset
OHLCDataItem[] data;
//This is where we go get the data, replace with your own data source
data = getData(stockSymbol);
//Create a dataset, an Open, High, Low, Close dataset
result = new DefaultOHLCDataset(stockSymbol, data);
return result;
}
//This method uses yahoo finance to get the OHLC data
protected OHLCDataItem[] getData(String stockSymbol) {
List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>();
try {
//INTERNET DATA
// String strUrl= "http://ichart.finance.yahoo.com/table.csv?s="+stockSymbol+"&a=0&b=1&c=2008&d=3&e=30&f=2008&ignore=.csv";
// URL url = new URL(strUrl);
// BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
// DateFormat df = new SimpleDateFormat("y-M-d");
//BEGIN
FileReader r;
BufferedReader in;
r = new FileReader("nasdaqSmall.csv");
in = new BufferedReader(r);
DateFormat df = new SimpleDateFormat("y-M-d");
//END
String inputLine;
in.readLine();
while ((inputLine = in.readLine()) != null) {
StringTokenizer st = new StringTokenizer(inputLine, ",");
Date date = df.parse( st.nextToken() );
double open = Double.parseDouble( st.nextToken() );
double high = Double.parseDouble( st.nextToken() );
double low = Double.parseDouble( st.nextToken() );
double close = Double.parseDouble( st.nextToken() );
double volume = Double.parseDouble( st.nextToken() );
double adjClose = Double.parseDouble( st.nextToken() );
OHLCDataItem item = new OHLCDataItem(date, open, high, low, close, volume);
dataItems.add(item);
}
in.close();
}
catch (Exception e) {
e.printStackTrace();
}
//Data from Yahoo is from newest to oldest. Reverse so it is oldest to newest
Collections.reverse(dataItems);
//Convert the list into an array
OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]);
//BEGIN
//DEBUG
printData(data);
//END
return data;
}
public static void main(String[] args) {
new CandlestickDemo("MSFT").setVisible(true);
}
//PRINT DATA
public static void printData(OHLCDataItem[] data){
for(OHLCDataItem el: data){
System.out.println(""+el.getDate()+" "+el.getOpen()+" "+el.getHigh()+" "+el.getLow()+" "+el.getClose()+
" "+el.getVolume());
}
}
}
我看不出所有 validate/repaints 会有什么帮助。作为一般规则,如果您要更改容器的布局管理器,请先执行此操作,然后再向其添加组件。
JFrame 包含一个 JRootPane,它有一个 contentPane。从技术上讲,您也需要在这个 contentPane 中添加组件。您可以使用框架的 getContentPane()
方法来实现这一点。但这确实变得很麻烦,因此 JFrame 变得更易于使用。来自文档:
As a conveniance add and its variants, remove and setLayout have been
overridden to forward to the contentPane as necessary. This means you
can write:
frame.add(child);
And the child will be added to the contentPane.
但我不记得什么时候添加了这种便利 - 可能 Java6 所以请确保您至少使用 jdk1.6。
另一件需要注意的事情是 contentPane 的默认布局:
The default content pane will have a BorderLayout manager set on it.
因此也无需将框架设置为使用 BorderLayout。使用 BorderLayout 时,您应该在添加组件时提供位置,例如BorderLayout.CENTER
。碰巧的是,我认为这不是导致错误的原因,因为我认为默认情况下它假定为 CENTER。但是,这仍然是一种很好的做法。
我必须承认,我总是使用更冗长的版本并通过 getContentPane()
直接与 JFrames 上的 add()
和 setLayout()
进行交互,而不是主要来自习惯的便捷方法,但确实如此说清楚我实际上在做什么。我建议您现在也这样做。
我创建了一个更小、更简单的应用程序版本,显示了供您使用的图表。
import javax.swing.*;
import java.awt.*;
import org.jfree.chart.*;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
class Test {
private JFrame frame;
public Test() {
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel aPanel = new JPanel();
aPanel.setPreferredSize(new Dimension(600, 300));
ChartPanel chartPanel = new ChartPanel(createChart());
chartPanel.setPreferredSize(new Dimension(600, 300));
frame.getContentPane().add(chartPanel);
frame.pack();
frame.setVisible(true);
}
private JFreeChart createChart() {
TimeSeries series = new TimeSeries("time series", Day.class);
series.add(new Day(1,1,2014), 100 );
series.add(new Day(1,2,2014), 150);
series.add(new Day(1,3,2014), 70 );
series.add(new Day(1,4,2014), 210 );
series.add(new Day(1,5,2014), 310);
series.add(new Day(1,6,2014), 260 );
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(series);
JFreeChart timechart = ChartFactory.createTimeSeriesChart(
"Vistors Count Chart", // Title
"Date", // X-axis Label
"Visitors", // Y-axis Label
dataset, // Dataset
true, // Show legend
true, // Use tooltips
false // Generate URLs
);
return timechart;
}
public static void main(String[] args) {
new Test();
}
}
这适用于 java/javac 1.7; jcommon-1.0.23; jfreechart-1.0.19.
试试这个:
您的 class 应该 extends
来自 import org.jfree.ui.
包的 ApplicationFrame
。
现在不用 frame.getContentPane()
使用 setContentPane(myChartPanel)
.
您的代码应该如下所示:
final JFreeChart myChart = createChart(dataset);
final ChartPanel myChartPanel = new ChartPanel(myChart);
myChartPanel.setPreferredSize(new java.awt.Dimension(500, 500));
setContentPane(myChartPanel);
我也遇到了这个问题。它来自将 JFreeChart 库中的所有 jar 添加到构建路径。通过删除不必要的并仅添加 jfreechart-1.0.19 和 jcommon-1.0.23 jar,我的应用程序开始了 运行 window 并显示图表。
我 运行 代码基于 here 在 OS X 上使用 Eclipse 所示的示例,我正在使用 JFreeChart 和 JCommon 库。
正如我在标题中所说,该程序 运行 但不显示任何内容。 作为检查,我尝试使用 printData() 方法打印数据,它运行良好。 它正确地从雅虎 csv 文件中获取数据。
我什至尝试使用一小部分数据(20 行),但它一直不显示。
问题可能在于显示 JFrame window。
我插入的试图修复它的代码位于 //BEGIN 和 //END 注释之间。
等待回复,
谢谢。
SEMI-SOLVED: 代码没问题,问题出在JFreeChart库上。
我试图在另一个以前工作的 JFrame class 中 "Build Path> Add my JFreeChart lib"。
当我插入 JFreeChart 库时,它会抑制 window 显示。即使我什么都不进口;只需将库添加到构建路径即可。
作为默认系统库,我使用 "JRE System Library [JavaSE-1.7]"。
代码:
package marketAnalyzer;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.MovingAverage;
import org.jfree.data.xy.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.text.*;
import java.util.*;
import java.util.List;
public class CandlestickDemo extends JFrame {
public CandlestickDemo(String stockSymbol) {
super("CandlestickDemo");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DateAxis domainAxis = new DateAxis("Date");
NumberAxis rangeAxis = new NumberAxis("Price");
CandlestickRenderer renderer = new CandlestickRenderer();
XYDataset dataset = getDataSet(stockSymbol);
XYPlot mainPlot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
final long ONE_DAY = 24 * 60 * 60 * 1000;
XYLineAndShapeRenderer maRenderer = new XYLineAndShapeRenderer(true, false);
XYDataset maSataset = MovingAverage.createMovingAverage(dataset, "MA", 30 * ONE_DAY, 0);
mainPlot.setRenderer(1, maRenderer);
mainPlot.setDataset (1, maSataset);
//Do some setting up, see the API Doc
renderer.setSeriesPaint(0, Color.BLACK);
renderer.setDrawVolume(false);
rangeAxis.setAutoRangeIncludesZero(false);
domainAxis.setTimeline( SegmentedTimeline.newMondayThroughFridayTimeline() );
//Now create the chart and chart panel
JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(600, 300));
this.add(chartPanel);
this.pack();
//BEGIN
//TRYING TO DISPLAY THE WINDOW
chartPanel.setLayout(new java.awt.BorderLayout());
chartPanel.validate();
this.setLayout(new java.awt.BorderLayout());
this.validate();
chartPanel.repaint();
this.repaint();
//END
}
protected AbstractXYDataset getDataSet(String stockSymbol) {
//This is the dataset we are going to create
DefaultOHLCDataset result = null;
//This is the data needed for the dataset
OHLCDataItem[] data;
//This is where we go get the data, replace with your own data source
data = getData(stockSymbol);
//Create a dataset, an Open, High, Low, Close dataset
result = new DefaultOHLCDataset(stockSymbol, data);
return result;
}
//This method uses yahoo finance to get the OHLC data
protected OHLCDataItem[] getData(String stockSymbol) {
List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>();
try {
//INTERNET DATA
// String strUrl= "http://ichart.finance.yahoo.com/table.csv?s="+stockSymbol+"&a=0&b=1&c=2008&d=3&e=30&f=2008&ignore=.csv";
// URL url = new URL(strUrl);
// BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
// DateFormat df = new SimpleDateFormat("y-M-d");
//BEGIN
FileReader r;
BufferedReader in;
r = new FileReader("nasdaqSmall.csv");
in = new BufferedReader(r);
DateFormat df = new SimpleDateFormat("y-M-d");
//END
String inputLine;
in.readLine();
while ((inputLine = in.readLine()) != null) {
StringTokenizer st = new StringTokenizer(inputLine, ",");
Date date = df.parse( st.nextToken() );
double open = Double.parseDouble( st.nextToken() );
double high = Double.parseDouble( st.nextToken() );
double low = Double.parseDouble( st.nextToken() );
double close = Double.parseDouble( st.nextToken() );
double volume = Double.parseDouble( st.nextToken() );
double adjClose = Double.parseDouble( st.nextToken() );
OHLCDataItem item = new OHLCDataItem(date, open, high, low, close, volume);
dataItems.add(item);
}
in.close();
}
catch (Exception e) {
e.printStackTrace();
}
//Data from Yahoo is from newest to oldest. Reverse so it is oldest to newest
Collections.reverse(dataItems);
//Convert the list into an array
OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]);
//BEGIN
//DEBUG
printData(data);
//END
return data;
}
public static void main(String[] args) {
new CandlestickDemo("MSFT").setVisible(true);
}
//PRINT DATA
public static void printData(OHLCDataItem[] data){
for(OHLCDataItem el: data){
System.out.println(""+el.getDate()+" "+el.getOpen()+" "+el.getHigh()+" "+el.getLow()+" "+el.getClose()+
" "+el.getVolume());
}
}
}
我看不出所有 validate/repaints 会有什么帮助。作为一般规则,如果您要更改容器的布局管理器,请先执行此操作,然后再向其添加组件。
JFrame 包含一个 JRootPane,它有一个 contentPane。从技术上讲,您也需要在这个 contentPane 中添加组件。您可以使用框架的 getContentPane()
方法来实现这一点。但这确实变得很麻烦,因此 JFrame 变得更易于使用。来自文档:
As a conveniance add and its variants, remove and setLayout have been overridden to forward to the contentPane as necessary. This means you can write:
frame.add(child);
And the child will be added to the contentPane.
但我不记得什么时候添加了这种便利 - 可能 Java6 所以请确保您至少使用 jdk1.6。
另一件需要注意的事情是 contentPane 的默认布局:
The default content pane will have a BorderLayout manager set on it.
因此也无需将框架设置为使用 BorderLayout。使用 BorderLayout 时,您应该在添加组件时提供位置,例如BorderLayout.CENTER
。碰巧的是,我认为这不是导致错误的原因,因为我认为默认情况下它假定为 CENTER。但是,这仍然是一种很好的做法。
我必须承认,我总是使用更冗长的版本并通过 getContentPane()
直接与 JFrames 上的 add()
和 setLayout()
进行交互,而不是主要来自习惯的便捷方法,但确实如此说清楚我实际上在做什么。我建议您现在也这样做。
我创建了一个更小、更简单的应用程序版本,显示了供您使用的图表。
import javax.swing.*;
import java.awt.*;
import org.jfree.chart.*;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
class Test {
private JFrame frame;
public Test() {
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel aPanel = new JPanel();
aPanel.setPreferredSize(new Dimension(600, 300));
ChartPanel chartPanel = new ChartPanel(createChart());
chartPanel.setPreferredSize(new Dimension(600, 300));
frame.getContentPane().add(chartPanel);
frame.pack();
frame.setVisible(true);
}
private JFreeChart createChart() {
TimeSeries series = new TimeSeries("time series", Day.class);
series.add(new Day(1,1,2014), 100 );
series.add(new Day(1,2,2014), 150);
series.add(new Day(1,3,2014), 70 );
series.add(new Day(1,4,2014), 210 );
series.add(new Day(1,5,2014), 310);
series.add(new Day(1,6,2014), 260 );
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(series);
JFreeChart timechart = ChartFactory.createTimeSeriesChart(
"Vistors Count Chart", // Title
"Date", // X-axis Label
"Visitors", // Y-axis Label
dataset, // Dataset
true, // Show legend
true, // Use tooltips
false // Generate URLs
);
return timechart;
}
public static void main(String[] args) {
new Test();
}
}
这适用于 java/javac 1.7; jcommon-1.0.23; jfreechart-1.0.19.
试试这个:
您的 class 应该 extends
来自 import org.jfree.ui.
包的 ApplicationFrame
。
现在不用 frame.getContentPane()
使用 setContentPane(myChartPanel)
.
您的代码应该如下所示:
final JFreeChart myChart = createChart(dataset);
final ChartPanel myChartPanel = new ChartPanel(myChart);
myChartPanel.setPreferredSize(new java.awt.Dimension(500, 500));
setContentPane(myChartPanel);
我也遇到了这个问题。它来自将 JFreeChart 库中的所有 jar 添加到构建路径。通过删除不必要的并仅添加 jfreechart-1.0.19 和 jcommon-1.0.23 jar,我的应用程序开始了 运行 window 并显示图表。