在 ListCellRenderer 中呈现 JList 内容时出现 OutOfMemoryError
OutOfMemoryError while rendering JList content in a ListCellRenderer
我试图在 JList 的图表中表示一些数据。在我创建 ChartPanels 的 JList 之前。现在我正在尝试 XYSeriesCollection
的 JList,然后在自定义 ListCellRenderer
.
中呈现其内容
但是我在尝试通过拖动光标滚动 JScrollpane 时遇到了 OutOfMemoryError
。
Java 虚拟机选项:-d64 -Xmx400m
为什么会这样?我应该在渲染中更改什么?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @see
*/
public class ThumbnailChartsJList{
public static JScrollPane scrollPane;
public static JList<XYSeriesCollection> chartList;
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("Test");
JPanel panel = new JPanel(new BorderLayout());
chartList = new ChartList();
scrollPane = new JScrollPane(chartList,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scrollPane, BorderLayout.CENTER);
f.setPreferredSize(new Dimension(1000,700));
f.setContentPane(panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
class ChartList extends JList<XYSeriesCollection>{
private static final Random random = new Random();
private static final int NumberCharts = 50;
private static final int Samples = 200;
private static final int W = 300;
private static final int H = W;
ChartList(){
DefaultListModel<XYSeriesCollection> listModel = new DefaultListModel<XYSeriesCollection>();
for (int i=0; i<NumberCharts; i++){
XYSeriesCollection serie = createRandomSerie();
listModel.addElement(serie);
}
this.setModel(listModel);
this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
this.setCellRenderer(new ChartListRenderer());
this.setVisibleRowCount(0); //0 - dynamic rows
this.setLayoutOrientation(JList.HORIZONTAL_WRAP);
this.setSelectionForeground(Color.RED);
}
private static XYSeriesCollection createRandomSerie() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(Samples) + Samples; i++) {
series.add(i, random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
static class ChartListRenderer implements ListCellRenderer<XYSeriesCollection> {
@Override
public Component getListCellRendererComponent(JList<? extends XYSeriesCollection> chartList, XYSeriesCollection serie, int index,
boolean isSelected, boolean cellHasFocus) {
JFreeChart chart = ChartFactory.createXYLineChart("Random", "counts", "samples", serie);
ChartPanel chartPanel = new ChartPanel(chart, true, true, true, false, true){
@Override
public Dimension getPreferredSize() {
return new Dimension(W, H);}
};
return chartPanel;
}
}
}
尝试仅使用一个 JFreeChart 和一个 ChartPanel 并将其重新用于您的渲染器。当前,您正在为每个单元格中的每个绘制请求创建一个新图表。
所以这些对象应该是您的 class 的成员对象,并且根据请求设置数据和 return 图表面板。
编辑:
这是一个例子。我不知道确切的方法签名,所以我只是将方法命名为 'setData':
static class ChartListRenderer implements ListCellRenderer<XYSeriesCollection> {
private JFreeChart chart = ChartFactory.createXYLineChart("Random", "counts", "samples");
private ChartPanel chartPanel = new ChartPanel(chart, true, true, true, false, true){
@Override
public Dimension getPreferredSize() {
return new Dimension(W, H);}
};
@Override
public Component getListCellRendererComponent(JList<? extends XYSeriesCollection> chartList, XYSeriesCollection serie, int index,
boolean isSelected, boolean cellHasFocus) {
chart.setData(serie);
return chartPanel;
}
}
正如@PaL 所建议的那样,您的ListCellRenderer
可以创建单个 JFreeChart
实例及其封闭的ChartPanel
.当调用渲染器的 getListCellRendererComponent()
实现时,它可以简单地更新图表绘图使用的数据集。结果在所示的小堆中很容易运行。
@Override
public Component getListCellRendererComponent(
JList modelList, XYSeriesCollection series,
int index, boolean isSelected, boolean hasFocus) {
XYPlot plot = chart.getXYPlot();
plot.setDataset(series);
return chartPanel;
}
经测试:$ java -d64 -Xmx64m -cp .:$JFREE_LIB/* ModelListTest
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @see
* @see
*/
public class ModelListTest {
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("Test");
f.add(new JScrollPane(new ModelList()));
f.pack();
f.setSize(640, 480);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
private static class ModelList extends JList<XYSeriesCollection> {
private static final Random random = new Random();
private static final int charts = 50;
private static final int samples = 200;
private static final int W = 300;
private static final int H = W;
ModelList() {
DefaultListModel<XYSeriesCollection> listModel = new DefaultListModel<>();
for (int i = 0; i < charts; i++) {
listModel.addElement(createRandomSeries());
}
this.setModel(listModel);
this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
this.setCellRenderer(new ModelListRenderer());
this.setVisibleRowCount(0);
this.setLayoutOrientation(JList.HORIZONTAL_WRAP);
this.setSelectionForeground(Color.RED);
}
private static XYSeriesCollection createRandomSeries() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(samples) + samples; i++) {
series.add(i, random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
private static class ModelListRenderer implements ListCellRenderer<XYSeriesCollection> {
private JFreeChart chart;
private ChartPanel chartPanel;
public ModelListRenderer() {
chart = ChartFactory.createXYLineChart("Random", "counts", "samples", null);
chartPanel = new ChartPanel(chart, true, true, true, false, true) {
@Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
};
}
@Override
public Component getListCellRendererComponent(
JList modelList, XYSeriesCollection series, int index, boolean isSelected, boolean hasFocus) {
XYPlot plot = chart.getXYPlot();
plot.setDataset(series);
return chartPanel;
}
}
}
}
我试图在 JList 的图表中表示一些数据。在我创建 ChartPanels XYSeriesCollection
的 JList,然后在自定义 ListCellRenderer
.
但是我在尝试通过拖动光标滚动 JScrollpane 时遇到了 OutOfMemoryError
。
Java 虚拟机选项:-d64 -Xmx400m
为什么会这样?我应该在渲染中更改什么?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @see
*/
public class ThumbnailChartsJList{
public static JScrollPane scrollPane;
public static JList<XYSeriesCollection> chartList;
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("Test");
JPanel panel = new JPanel(new BorderLayout());
chartList = new ChartList();
scrollPane = new JScrollPane(chartList,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scrollPane, BorderLayout.CENTER);
f.setPreferredSize(new Dimension(1000,700));
f.setContentPane(panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
class ChartList extends JList<XYSeriesCollection>{
private static final Random random = new Random();
private static final int NumberCharts = 50;
private static final int Samples = 200;
private static final int W = 300;
private static final int H = W;
ChartList(){
DefaultListModel<XYSeriesCollection> listModel = new DefaultListModel<XYSeriesCollection>();
for (int i=0; i<NumberCharts; i++){
XYSeriesCollection serie = createRandomSerie();
listModel.addElement(serie);
}
this.setModel(listModel);
this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
this.setCellRenderer(new ChartListRenderer());
this.setVisibleRowCount(0); //0 - dynamic rows
this.setLayoutOrientation(JList.HORIZONTAL_WRAP);
this.setSelectionForeground(Color.RED);
}
private static XYSeriesCollection createRandomSerie() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(Samples) + Samples; i++) {
series.add(i, random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
static class ChartListRenderer implements ListCellRenderer<XYSeriesCollection> {
@Override
public Component getListCellRendererComponent(JList<? extends XYSeriesCollection> chartList, XYSeriesCollection serie, int index,
boolean isSelected, boolean cellHasFocus) {
JFreeChart chart = ChartFactory.createXYLineChart("Random", "counts", "samples", serie);
ChartPanel chartPanel = new ChartPanel(chart, true, true, true, false, true){
@Override
public Dimension getPreferredSize() {
return new Dimension(W, H);}
};
return chartPanel;
}
}
}
尝试仅使用一个 JFreeChart 和一个 ChartPanel 并将其重新用于您的渲染器。当前,您正在为每个单元格中的每个绘制请求创建一个新图表。
所以这些对象应该是您的 class 的成员对象,并且根据请求设置数据和 return 图表面板。
编辑:
这是一个例子。我不知道确切的方法签名,所以我只是将方法命名为 'setData':
static class ChartListRenderer implements ListCellRenderer<XYSeriesCollection> {
private JFreeChart chart = ChartFactory.createXYLineChart("Random", "counts", "samples");
private ChartPanel chartPanel = new ChartPanel(chart, true, true, true, false, true){
@Override
public Dimension getPreferredSize() {
return new Dimension(W, H);}
};
@Override
public Component getListCellRendererComponent(JList<? extends XYSeriesCollection> chartList, XYSeriesCollection serie, int index,
boolean isSelected, boolean cellHasFocus) {
chart.setData(serie);
return chartPanel;
}
}
正如@PaL 所建议的那样ListCellRenderer
可以创建单个 JFreeChart
实例及其封闭的ChartPanel
.当调用渲染器的 getListCellRendererComponent()
实现时,它可以简单地更新图表绘图使用的数据集。结果在所示的小堆中很容易运行。
@Override
public Component getListCellRendererComponent(
JList modelList, XYSeriesCollection series,
int index, boolean isSelected, boolean hasFocus) {
XYPlot plot = chart.getXYPlot();
plot.setDataset(series);
return chartPanel;
}
经测试:$ java -d64 -Xmx64m -cp .:$JFREE_LIB/* ModelListTest
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @see
* @see
*/
public class ModelListTest {
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("Test");
f.add(new JScrollPane(new ModelList()));
f.pack();
f.setSize(640, 480);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
private static class ModelList extends JList<XYSeriesCollection> {
private static final Random random = new Random();
private static final int charts = 50;
private static final int samples = 200;
private static final int W = 300;
private static final int H = W;
ModelList() {
DefaultListModel<XYSeriesCollection> listModel = new DefaultListModel<>();
for (int i = 0; i < charts; i++) {
listModel.addElement(createRandomSeries());
}
this.setModel(listModel);
this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
this.setCellRenderer(new ModelListRenderer());
this.setVisibleRowCount(0);
this.setLayoutOrientation(JList.HORIZONTAL_WRAP);
this.setSelectionForeground(Color.RED);
}
private static XYSeriesCollection createRandomSeries() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(samples) + samples; i++) {
series.add(i, random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
private static class ModelListRenderer implements ListCellRenderer<XYSeriesCollection> {
private JFreeChart chart;
private ChartPanel chartPanel;
public ModelListRenderer() {
chart = ChartFactory.createXYLineChart("Random", "counts", "samples", null);
chartPanel = new ChartPanel(chart, true, true, true, false, true) {
@Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
};
}
@Override
public Component getListCellRendererComponent(
JList modelList, XYSeriesCollection series, int index, boolean isSelected, boolean hasFocus) {
XYPlot plot = chart.getXYPlot();
plot.setDataset(series);
return chartPanel;
}
}
}
}