2017-07-09 22 views
0

これは私の最初の投稿StackOverFlowですので、私の投稿の間違いをお許しください。 トピックには、特定のX座標とY座標をプロットするプログラムがあります。 私は現在、XYチャートにJFREECHARTを使用しています。 高速アップデートの要件を満たすために、私は2シリーズを持っています。 Series1は1000のデータポイントを蓄積し、それを表示するためにチャートに追加されます。このシリーズ2は1000データポイントを蓄積し、一度確定されるとシリーズ1000をクリアし(新しい1000データポイントの準備をします)、シリーズ2をチャートに追加します)...そしてこのサイクルは続く。 問題はXYSeries.clearおよびXYSeries.add関数にあります。どうやら彼らは自分のスレッドを作成し、実行が完了する前に、私のアプリケーションが非常に高速であるので、すでに新しいスレッドを生成しています。これは私が考えているindexoutoboundsエラーです。私はこれを推測することができました: http://www.jfree.org/phpBB2/viewtopic.php?p=68111 類似したエラー。 解決策は次のようになります。 Swing Thread Safe ProgrammingJfreechart indexoutofbounds例外

解決策は、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); 

    } 
} 
+1

です。通常、リアルタイムGUIグラフ作成を試みる前に、オブジェクト指向とスレッディングの概念を学ぶのが最善です。少しバックアップを取っておこうと思っているかもしれませんし、先に進める前にこれらの基礎を徹底的に勉強して、あなたが深刻な不満のためにいるかもしれないことを恐れています。 –

+0

ただ一つのシリーズでも、私は要素を追加し、要素を削除してindexoutofboundエラーを出します。大きなスリープ間隔でエラーが表示されません。 私は、2つのスレッド を作成することを考えています.1つはデータ蓄積用、もう1つはGUI更新用ですが、ADDメソッドとREMOVEメソッドを1つずつ呼び出して呼び出すと、主な問題が作成されます。 – EgLeO

+0

JFreeChartの小さなサブセットを読んだ後では、synchronizedをまったく使用しないので、あなたは役に立たない... – Aubin

答えて

1

スイングはスレッドセーフではありません。 hereのように、Swingイベントポンプスレッド以外のスレッドからSwingUtilities.invokeLater(...)を使用する必要があります。

tutorial about Swingが参考になる場合があります。

ここではオブジェクト指向の提案があります。お役に立てれば。たくさんAUBINへ

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()); 
    } 
} 
+1

また、検討されているアプローチの1つを検討します(https://stackoverflow.com/q/5048852/230513)。 )。 – trashgod

+1

コードを確認して勉強していただきありがとうございます。 ご意見ありがとうございました。私は私の目的に合うように私がそれを使用できるかどうかを見るために時系列を調べています。 – EgLeO

0

おかげで、私はエラーなしで最終と高速作業コードを得ました。最終的なコードは

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()); 
    } 
} 
関連する問題