【发布时间】:2017-07-09 03:03:09
【问题描述】:
这是我第一次在 StackOverFlow 上发帖,所以请原谅我帖子中的任何错误。 谈到这个话题,我有一个程序应该绘制某些 X 和 Y 坐标。 我目前正在为 XYChart 使用 JFREECHART。 为了满足高速更新的要求,我有2个系列。 Series1 累积 1000 个数据点,然后添加到图表中以显示它。在此 series2 累积 1000 个数据点之后,一旦完成,它就会清除 series1(为新的 1000 个数据点做准备)并将 series2 附加到图表(现在有 1000 个数据点) )...这个循环还在继续。 问题在于 XYSeries.clear 和 XYSeries.add 函数。显然他们创建了自己的线程,在他们完成执行之前我已经产生了一个新线程,因为我的应用程序非常快。我认为这会导致 indexoutobounds 错误。我可以通过以下方式猜到这一点: http://www.jfree.org/phpBB2/viewtopic.php?p=68111 类似的错误。 解决方案似乎是: Swing Thread Safe Programming
这里的解决方案是使用 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);
}
}
【问题讨论】:
-
您似乎本末倒置,因为通常最好在尝试进行实时 GUI 图形之前学习面向对象和线程概念。在继续之前,您可能希望考虑备份并深入研究这些基础知识,否则我担心您可能会感到非常沮丧。
-
即使只有一个系列,我在其中添加元素和删除元素也会给出 indexoutofbound 错误。睡眠间隔较大时不会出现该错误。我正在考虑创建 2 个线程,1 个用于数据积累,1 个用于 GUI 更新,但是一个接一个地调用 ADD 方法和 REMOVE 方法是主要问题。
-
看了一小部分JFreeChart后,根本没有使用同步,所以你的没用...
标签: java swing thread-safety jfreechart