Java 从线程更新JFreeChart
我必须建立一个GPS解析器。我需要在另一个线程中解析NMEA字符串,该线程将解析单个NMEA字符串并以1Hz的频率更新图表。现在我构建了部分代码,但我在while循环中解析主线程中的数据;我的老师说那是错误的。我是在Java上编程的,但不是在多线程方面。如何将解析过程和刷新图表移动到后台线程Java 从线程更新JFreeChart,java,multithreading,swing,jfreechart,Java,Multithreading,Swing,Jfreechart,我必须建立一个GPS解析器。我需要在另一个线程中解析NMEA字符串,该线程将解析单个NMEA字符串并以1Hz的频率更新图表。现在我构建了部分代码,但我在while循环中解析主线程中的数据;我的老师说那是错误的。我是在Java上编程的,但不是在多线程方面。如何将解析过程和刷新图表移动到后台线程 public class MainFrame extends JFrame { private JButton btnWybPlik; private JLabel jlDroga;
public class MainFrame extends JFrame {
private JButton btnWybPlik;
private JLabel jlDroga;
private JLabel jlPredkosc;
private JLabel jlCzas;
private JPanel mainjpanel;
private JPanel jpMenu;
private JPanel jpTablica;
//private String sciezkaPliku;
private SekwencjaGGA sekGGA = null;
private SekwencjaGGA popSekGGA = null;
private SekwencjaGSA sekGSA;
private SekwencjaGLL sekGLL;
private SekwencjaRMC sekRMC;
private double droga;
private double predkosc;
private XYSeries series1;
private XYSeriesCollection dataset;
public MainFrame() {
droga = 0;
btnWybPlik.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
int result = fileChooser.showOpenDialog(mainjpanel);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
//System.out.println("Selected file: " + selectedFile.getAbsolutePath());
String sciezkaPliku = selectedFile.getAbsolutePath();
wczytaniePliku(sciezkaPliku);
}
}
});
jpTablica = new JPanel();
mainjpanel.add(jpTablica);
this.series1 = new XYSeries("Trasa", false);
final XYSeriesCollection dataset = new XYSeriesCollection(this.series1);
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
jpTablica.add(chartPanel);
}
private void wczytaniePliku(String sciezkaDoPliku) {
try (BufferedReader br = new BufferedReader(new FileReader(sciezkaDoPliku))) {
String line;
//series1.add(53.448, 14.4907);
while ((line = br.readLine()) != null) {
parseLine(line);
}
//series1.add(53.4485, 14.4910);
} catch (IOException e) {
e.printStackTrace();
}
}
private void parseLine(String line) {
String bezSumKont = line.substring(0, line.length() - 3);
List<String> podzSekw = Arrays.asList(bezSumKont.split(","));
if (podzSekw.get(0).equalsIgnoreCase("$GPGGA")) {
if (check(line)) {
if (sekGGA != null)
popSekGGA = sekGGA;
sekGGA = new SekwencjaGGA(podzSekw);
if (popSekGGA != null) {
droga += obliczOdleglosc(popSekGGA, sekGGA);
jlDroga.setText(String.valueOf(droga));
}
series1.add(sekGGA.getWspolzedne().getLongitude(), sekGGA.getWspolzedne().getLatitude());
System.out.println(sekGGA.getWspolzedne().getLatitude() + " " + sekGGA.getWspolzedne().getLongitude());
//System.out.println(series1.getMaxY() + " " + series1.getMinY());
} else {
//TODO: Zlicz błąd
}
}
if (podzSekw.get(0).equalsIgnoreCase("$GPGSA")) {
if (check(line)) {
sekGSA = new SekwencjaGSA(podzSekw);
} else {
//TODO: Zlicz błąd
}
}
if (podzSekw.get(0).equalsIgnoreCase("$GPGLL")) {
if (check(line)) {
sekGLL = new SekwencjaGLL(podzSekw);
} else {
//TODO: Zlicz błąd
}
}
if (podzSekw.get(0).equalsIgnoreCase("$GPRMC")) {
//TODO: Sekwencja RMC (Recommended minimum of data)
if (check(line)) {
sekRMC = new SekwencjaRMC(podzSekw);
} else {
//TODO: Zlicz błąd
}
}
}
private double obliczOdleglosc(SekwencjaGGA pkt1, SekwencjaGGA pkt2) {
double odleglosc = 0;
double earthRadius = 6371000; //meters
double dLat = Math.toRadians(pkt2.getWspolzedne().getLatitude() - pkt1.getWspolzedne().getLatitude());
double dLng = Math.toRadians(pkt2.getWspolzedne().getLongitude() - pkt1.getWspolzedne().getLongitude());
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())) * Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
odleglosc = earthRadius * c;
return odleglosc;
}
/**
* Funkcja sprawdzająca sume kontrolną
*
* @param tekst cała linia NMEA
* @return true jeśli się suma kontrolna zgadza
*/
private boolean check(String tekst) {
String suma = tekst.substring(tekst.length() - 2, tekst.length());
tekst = tekst.substring(1, tekst.length() - 3);
int checksum = 0;
for (int i = 0; i < tekst.length(); i++) {
checksum = checksum ^ tekst.charAt(i);
}
if (Integer.parseInt(suma, 16) == checksum) {
return true;
}
return false;
}
private JFreeChart createChart(final XYDataset dataset) { ... }
private void customizeChart(JFreeChart chart) { ... }
public static void main(String[] args) {
JFrame frame = new JFrame("MainFrame");
frame.setContentPane(new MainFrame().mainjpanel);
frame.setPreferredSize(new Dimension(640, 480));
frame.pack();
frame.setVisible(true);
}
公共类大型机扩展JFrame{
私人JButton btnWybPlik;
私人JLabel jlDroga;
私人JLabel jlPredkosc;
私人JLabel jlCzas;
私人JPanel mainjpanel;
私有JPanel jpMenu;
私人JPanel jpTablica;
//私人字符串sciezkaPliku;
私有SekwencjaGGA sekGGA=null;
私有SekwencjaGGA-popSekGGA=null;
私营企业SekwencjaGSA sekGSA;
私人SekwencjaGLL sekGLL;
私营企业SekwencjaRMC sekRMC;
私人双卓加;
私人双普雷德科斯克;
私有XY系列1;
私有XYSeriesCollection数据集;
公共主机(){
droga=0;
btnWybPlik.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
JFileChooser fileChooser=新的JFileChooser();
fileChooser.setCurrentDirectory(新文件(System.getProperty(“user.home”));
int result=fileChooser.showOpenDialog(mainjpanel);
if(result==JFileChooser.APPROVE\u选项){
File selectedFile=fileChooser.getSelectedFile();
//System.out.println(“所选文件:+selectedFile.getAbsolutePath());
字符串sciezkaPliku=selectedFile.getAbsolutePath();
wczytaniePliku(sciezkaPliku);
}
}
});
jpTablica=新的JPanel();
mainjpanel.add(jpTablica);
this.series1=新的XYSeries(“Trasa”,false);
最终XYSeriesCollection数据集=新的XYSeriesCollection(this.series1);
最终JFreeChart图表=createChart(数据集);
最终图表面板图表面板=新图表面板(图表);
jpTablica.add(图表面板);
}
私有void wczytaniePliku(字符串sciezkaDoPliku){
try(BufferedReader br=new BufferedReader(new FileReader(sciezkaDoPliku))){
弦线;
//系列1.添加(53.448,14.4907);
而((line=br.readLine())!=null){
行(行);
}
//系列1.增补(53.4485,14.4910);
}捕获(IOE异常){
e、 printStackTrace();
}
}
专用行(字符串行){
字符串bezzumkont=line.substring(0,line.length()-3);
List podzSekw=Arrays.asList(bezzumkont.split(“,”);
if(podzSekw.get(0.equalsIgnoreCase($GPGGA))){
如果(勾选(行)){
如果(sekGGA!=null)
popSekGGA=sekGGA;
sekGGA=新的SekwencjaGGA(podzSekw);
if(popSekGGA!=null){
droga+=斜交链(popSekGGA,sekGGA);
setText(String.valueOf(droga));
}
series1.add(sekGGA.getWspolzedne().getLongitude(),sekGGA.getWspolzedne().getLatitude());
System.out.println(sekGGA.getWspolzedne().getLatitude()+“”+sekGGA.getWspolzedne().getLatitude());
//System.out.println(series1.getMaxY()+“”+series1.getMinY());
}否则{
//待办事项:Zlicz błd
}
}
if(podzSekw.get(0.equalsIgnoreCase($GPGSA))){
如果(勾选(行)){
sekGSA=新SekwencjaGSA(podzSekw);
}否则{
//待办事项:Zlicz błd
}
}
if(podzSekw.get(0.equalsIgnoreCase($GPGLL))){
如果(勾选(行)){
sekGLL=新SekwencjaGLL(podzSekw);
}否则{
//待办事项:Zlicz błd
}
}
if(podzSekw.get(0.equalsIgnoreCase($GPRMC))){
//TODO:Sekwencja RMC(建议的最低数据)
如果(勾选(行)){
sekRMC=新的SekwencjaRMC(podzSekw);
}否则{
//待办事项:Zlicz błd
}
}
}
私人双债务人(SekwencjaGGA pkt1、SekwencjaGGA pkt2){
双odleglosc=0;
双接地半径=6371000;//米
double dLat=Math.toRadians(pkt2.getWspolzedne().getLatitude()-pkt1.getWspolzedne().getLatitude());
double dLng=Math.toRadians(pkt2.getWspolzedne().getLongitude()-pkt1.getWspolzedne().getLongitude());
双a=Math.sin(dLat/2)*Math.sin(dLat/2)+
Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude())*Math.cos(Math.toRadians(pkt1.getWspolzedne().getLatitude()))*
数学单(dLng/2)*数学单(dLng/2);
double c=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
odleglosc=地球半径*c;
返回odleglosc;
}
/**
*斯普拉德扎伊·苏姆·康特罗酒店
*
*@param tekst cała linia NMEA
*@return true jeśli sięsuma kontrolna zgadza
*/
专用布尔检查(字符串tekst){
字符串suma=tekst.substring(tekst.length()-2,tekst.length());
tekst=tekst子字符串(1,tekst长度()-3);
整数校验和=0;
对于(int i=0;i