[英]Jfreechart indexoutofbounds exception
這是我第一次在StackOverFlow上發帖,所以請原諒我的任何錯誤。 談到這個話題,我有一個程序應該繪制某些X和Y坐標。 我目前正在將JFREECHART用於XYChart。 為了滿足高速更新的要求,我提供了2個系列。 Series1累積1000個數據點,然后將其添加到圖表中以顯示它。此Series2累積1000個數據點並確定后,清除Series1(為新的1000個數據點做准備)並將series2附加到圖表(現在有1000個數據點) )...此循環繼續進行。 問題出在XYSeries.clear和XYSeries.add函數。 顯然,它們創建了自己的線程,在完成執行之前,我已經產生了一個新線程,因為我的應用程序運行速度非常快。 我認為這是導致indexoutobounds錯誤的原因。 我能夠通過以下方式猜出這一點: http : //www.jfree.org/phpBB2/viewtopic.php? p = 68111類似錯誤。 解決方案似乎是: Swing線程安全編程
這里的解決方案是使用SwingUtilities.invokeLater。 但是我不明白如何在我的應用程序中使用它。 我的代碼是:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import static java.lang.Thread.sleep;
import org.jfree.chart.axis.ValueAxis;
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.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class dataPlotter {
private static int x = 0;
private static boolean thread_start = false;
private static final double PI = 3.1428571;
private static boolean thread_run = true;
private static double voltage = 0;
private static boolean useSeries1 = true;
public static void main(String[] args) {
//create and configure window
JFrame window = new JFrame();
window.setTitle("Data Plotter GUI");
window.setSize(600, 400);
window.setLayout(new BorderLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create a drop down box and connect button, then place that at the top of the window
JButton connectButton = new JButton("Start");
JPanel topPanel = new JPanel();
topPanel.add(connectButton);
window.add(topPanel, BorderLayout.NORTH);
//create the line graph
XYSeries series1 = new XYSeries("Voltage Characteristics");
XYSeries series2 = new XYSeries("Voltage Characteristics");
XYSeriesCollection dataset = new XYSeriesCollection(series1);
JFreeChart chart = ChartFactory.createXYLineChart("Sine Wave", "Time", "Voltage", dataset);
window.add(new ChartPanel(chart), BorderLayout.CENTER);
//set range of x axis and range of series
XYPlot xyPlot = chart.getXYPlot();
ValueAxis domainAxis = xyPlot.getDomainAxis();
ValueAxis rangeAxis = xyPlot.getRangeAxis();
rangeAxis.setRange(-1.5, 1.5);
domainAxis.setRange(0, 1000);
//Declaring thread
Thread thread;
thread = new Thread() {
@Override
public void run() {
thread_start = true;
int count_y = 0;
thread_run = true;
int count = 0;
while (thread_run) {
//create "Y" datapoint i.e. voltage
if (count_y < 800) {
count_y++;
} else {
count_y = 0;
}
voltage = Math.sin(2 * PI * count_y / 800);
//add datapoint to CHART
try {
//use series 1 to accumulate 1000 datapoints
if(useSeries1){
synchronized (series1) {
if (series1.getItemCount() > 1000) {
domainAxis.setRange(x - 1001, x);
}
series1.add(x++, voltage);
sleep(1);
}
synchronized (series1) {
window.repaint();
}
synchronized (series1) {
if (series1.getItemCount() ==1001) {
dataset.removeAllSeries();
series2.clear();
domainAxis.setRange(0, 1000);
dataset.addSeries(series1);
useSeries1 = false;
sleep(5);
x = 0;
window.repaint();
}
}
} else{
synchronized (series2) {
if (series2.getItemCount() > 1000) {
domainAxis.setRange(x - 1001, x);
}
series2.add(x++, voltage);
sleep(1);
}
synchronized (series2) {
window.repaint();
}
synchronized (series2) {
if (series2.getItemCount() == 1001) {
dataset.removeAllSeries();
series1.clear();
domainAxis.setRange(0, 1000);
dataset.addSeries(series2);
useSeries1 = true;
sleep(5);
x = 0;
window.repaint();
}
}
}
} catch (Exception er) { }
}
thread_start = false;
}
};
//configure the connect button and use another thread to listen for data
connectButton.addActionListener(new ActionListener() {
@Override
@SuppressWarnings("empty-statement")
public void actionPerformed(ActionEvent e) {
if (connectButton.getText().equals("Start")) {
connectButton.setText("Stop");
thread.start();
} else {
//disconnect from the serial port
thread_run = false;
//while (thread_start);
connectButton.setText("Start");
//synchronized (series) {
//series.clear();
//}
//x = 0;
}
}
});
//Display winow
window.setVisible(true);
}
}
通過設計,秋千不是線程安全的。 您必須從此處討論的Swing事件泵線程之外的其他線程使用SwingUtilities.invokeLater( ... )
。
這是一個面向對象的建議。 希望這可以幫助。
public class Plotter implements Runnable {
private static final String BTN_START = "Start";
private static final String BTN_STOP = "Stop";
private final JFrame window = new JFrame();
private final JButton connectButton = new JButton( BTN_START );
private final XYSeries series1 = new XYSeries("Voltage Characteristics");
private final XYSeries series2 = new XYSeries("Voltage Characteristics");
private final XYSeriesCollection dataset = new XYSeriesCollection( series1 );
private final JFreeChart chart =
ChartFactory.createXYLineChart("Sine Wave", "Time", "Voltage", dataset);
private final XYPlot xyPlot = chart.getXYPlot();
private final ValueAxis domainAxis = xyPlot.getDomainAxis();
private final ValueAxis rangeAxis = xyPlot.getRangeAxis();
private /* */ Thread thread = null;
private /* */ boolean thread_run = true;
private /* */ double voltage = 0;
private /* */ boolean useSeries1 = true;
private /* */ int x = 0;
public Plotter() {
window.setTitle("Data Plotter GUI");
window.setSize(600, 400);
window.setLayout(new BorderLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel topPanel = new JPanel();
topPanel.add(connectButton);
window.add(topPanel, BorderLayout.NORTH);
window.add(new ChartPanel(chart), BorderLayout.CENTER);
rangeAxis.setRange(-1.5, 1.5);
domainAxis.setRange(0, 1000);
connectButton.addActionListener( e -> startOrStop());
window.setVisible(true);
}
private void startOrStop() {
if (connectButton.getText().equals( BTN_START )) {
connectButton.setText( BTN_STOP );
synchronized( series1 ) { series1.clear(); }
synchronized( series2 ) { series2.clear(); }
thread = new Thread( Plotter.this );
thread.setName( "Plotter" );
thread.setDaemon( true );
thread.start();
}
else {
thread_run = false;
//disconnect from the serial port
connectButton.setText( BTN_START );
try {
thread.join( 10_000L );
}
catch( final InterruptedException e ){
e.printStackTrace();
}
}
}
private void updateSeries1() {
if (series1.getItemCount() > 1000) {
domainAxis.setRange(x - 1001, x);
}
series1.add( x++, voltage );
window.repaint();
if (series1.getItemCount() ==1001) {
dataset.removeAllSeries();
series2.clear();
domainAxis.setRange(0, 1000);
dataset.addSeries(series1);
useSeries1 = false;
window.repaint();
x = 0;
}
}
private void updateSeries2() {
if (series2.getItemCount() > 1000) {
domainAxis.setRange(x - 1001, x);
}
series2.add( x++, voltage );
window.repaint();
if( series2.getItemCount() == 1001 ) {
dataset.removeAllSeries();
series1.clear();
domainAxis.setRange(0, 1000);
dataset.addSeries(series2);
useSeries1 = true;
window.repaint();
x = 0;
}
}
@Override
public void run() {
x = 0;
int count_y = 0;
thread_run = true;
while( thread_run ) {
if (count_y < 800) {
count_y++;
}
else {
count_y = 0;
}
voltage = Math.sin(( 2 * Math.PI * count_y ) / 800);
try {
// Push a new job in the Swing queue
if( useSeries1 ) {
SwingUtilities.invokeLater(() -> updateSeries1());
}
else {
SwingUtilities.invokeLater(() -> updateSeries2());
}
}
catch (final Exception er) {
er.printStackTrace();
}
try {
Thread.sleep( 2L ); // Give time to Swing to execute the job
}
catch( final InterruptedException e ){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Plotter());
}
}
非常感謝AUBIN,我得到了最終的高速工作代碼,沒有任何錯誤。 最終的代碼是:
import java.awt.BorderLayout;
import org.jfree.chart.axis.ValueAxis;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
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;
public class Plotter implements Runnable {
private static final String BTN_START = "Start";
private static final String BTN_STOP = "Stop";
private final JFrame window = new JFrame();
private final JButton connectButton = new JButton( BTN_START );
private final XYSeries series1 = new XYSeries("Voltage Characteristics");
private final XYSeries series2 = new XYSeries("Voltage Characteristics");
private final XYSeriesCollection dataset = new XYSeriesCollection( series2 );
private final JFreeChart chart = ChartFactory.createXYLineChart("Sine Wave", "Time", "Voltage", dataset);
private final XYPlot xyPlot = chart.getXYPlot();
private final ValueAxis domainAxis = xyPlot.getDomainAxis();
private final ValueAxis rangeAxis = xyPlot.getRangeAxis();
private /* */ Thread thread = null;
private /* */ boolean thread_run = true;
private /* */ double voltage = 0;
private /* */ boolean useSeries1 = true;
private /* */ int x = 0;
public Plotter() {
window.setTitle("Data Plotter GUI");
window.setSize(600, 400);
window.setLayout(new BorderLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel topPanel = new JPanel();
topPanel.add(connectButton);
window.add(topPanel, BorderLayout.NORTH);
window.add(new ChartPanel(chart), BorderLayout.CENTER);
rangeAxis.setRange(-1.5, 1.5);
domainAxis.setRange(0, 1000);
connectButton.addActionListener( e -> startOrStop());
window.setVisible(true);
}
private void startOrStop() {
if (connectButton.getText().equals( BTN_START )) {
connectButton.setText( BTN_STOP );
synchronized( series1 ) { series1.clear(); }
synchronized( series2 ) { series2.clear(); }
thread = new Thread( Plotter.this );
thread.setName( "Plotter" );
thread.setDaemon( true );
thread.start();
}
else {
thread_run = false;
//disconnect from the serial port
connectButton.setText( BTN_START );
try {
thread.join( 10_000L );
}
catch( final InterruptedException e ){
e.printStackTrace();
}
}
}
private void updateSeries1() {
if (series1.getItemCount() > 1000) {
domainAxis.setRange(x - 1001, x);
}
series1.add( x++, voltage );
//window.repaint();
if (series1.getItemCount() ==1001) {
dataset.removeAllSeries();
series2.clear();
domainAxis.setRange(0, 1000);
dataset.addSeries(series1);
useSeries1 = false;
window.repaint();
x = 0;
}
}
private void updateSeries2() {
if (series2.getItemCount() > 1000) {
domainAxis.setRange(x - 1001, x);
}
series2.add( x++, voltage );
//window.repaint();
if( series2.getItemCount() == 1001 ) {
dataset.removeAllSeries();
series1.clear();
domainAxis.setRange(0, 1000);
dataset.addSeries(series2);
useSeries1 = true;
window.repaint();
x = 0;
}
}
@Override
public void run() {
x = 0;
int count_y = 0;
thread_run = true;
while( thread_run ) {
if (count_y < 800) {
count_y++;
}
else {
count_y = 0;
}
voltage = Math.sin(( 2 * Math.PI * count_y ) / 800);
try {
// Push a new job in the Swing queue
if( useSeries1 ) {
SwingUtilities.invokeAndWait(() -> updateSeries1());
}
else {
SwingUtilities.invokeAndWait(() -> updateSeries2());
}
}
catch (final Exception er) {
er.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Plotter());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.