2013年1月12日土曜日

.Net (VC++) Chartクラスを使ってグラフを表示


先日作成した電子温度計(Stellaris LM4F120)とPCとの連携を行いたいと思い、測定データをPCに取り込み、データのグラフ表示を試しました。
以前VC++でグラフ表示を行った時 System::Drawing::Graphics等の Drawing配下のクラスを利用しましたが、今回は、Chartクラスを使ったグラフ表示を試しました。
 
===================================================================
1.概要
     電子温度計 [UART] ==(USB)== [COMポート]  PC
                      測定温度

  デザイン
   VC++でWindowsフォームアプリケーションでプロジェクトを作成する。
   Form1にChart、SerialPort オブジェクトを追加 設定する。

  初期処理
   Chart/Seriseに1024個のDataPointを値0で登録する。
  メイン処理  
   シリアルポート受信イベントで電子温度計が出力する温度データを取り込む。
   取り込んだ温度データを順次 Chart/Serise/DataPointオブジェクトに設定する。

===================================================================
2.VC++プロジェクト作成<<非時系列チャート>>
 1)Chart設定
   Form1にChartオブジェクト chart1 を作成
     プロパティ設定 Seriseコレクション(ChartType:Line)
 2)SerialPort設定
   Form1にSerialPortオブジェクト serialPort1を作成
     プロパティ設定 BaudRate と PortNameを設定
   
   
 3)コーディング コンストラクタ Form1(void)
   ①Charting/Seriesオブジェクト series1tをローカル宣言
     System::Windows::Forms::DataVisualization::Charting::Series^  series1t;
   ②chart1のSeries1を①で宣言したseries1tに読みだす。
     series1t = this->chart1->Series["Series1"];
   ③Charting/DataPointオブジェクトを初期値で作成。
     
     System::Windows:・・・:Charting::DataPoint^  tmppoint
      = (gcnew System::Windows::・・・::Charting::DataPoint(i,0));
   
   ④Charting/DataPointオブジェクトを①で宣言したseries1tに登録する。
     series1t->Points->Add(tmppoint);
   *③④を繰り返し1024のDataPointオブジェクトをseries1t(chart1/Series1)に登録する。

   ⑤シリアルポートをOpenする。
     this->serialPort1->Open();

 4)コーディング シリアルポート受信イベント処理 (serialPort1_DataReceived)
   ①Charting/Series、Pointsオブジェクト series1t、tmppoint をローカル宣言
   ②DateTime型で現在時刻を取得する。
     DateTime timesp =   System::DateTime::Now;
   ③シリアルポート受信データを取り込み、温度データを抽出する。
     strreceive = this->serialPort1->ReadLine();   [[strreceive:String]]
     strvalue = strreceive->Substring(7,6);  [[strvalue:String 温度データ位置:7]]
   ④取得した温度データでSeries1のDataPointを更新する。
     (インデックス指定で、一旦Series1のDataPointを削除して、取得した温度データでDataPointオブジェクトを作成し登録し直す。)
     series1t = this->chart1->Series["Series1"];
     tmppoint = series1t->Points[IntPointIndex];    [[IntPointIndex:DataPointインデックス]]
     series1t->Points->Remove(tmppoint);
     System::Windows:・・・:Charting::DataPoint^  tmppoint1
      = (gcnew System::Windows::Forms::DataVisualization::Charting::DataPoint(IntPointIndex,System::Convert::ToDouble(strvalue)));
     series1t->Points->Insert(IntPointIndex,tmppoint1);

  5)エラー対処
    このコーディングでプログラムを実行すると、不定期のタイミングで「InvalidOperationException ”コレクションが変更されました。実行されない可能性があります。” エラー」が発生します。
    ①原因の予想
      チャート表示処理中にチャート情報の更新が重なったため起きたエラーと思われます。
    ②対処
      Serise1/DataPointオブジェクトの削除、挿入処理はChartを一旦非表示にして実行する。
         this->chart1->Visible = false;       


===================================================================
3.VC++プロジェクト作成 <<時系列チャート>>

 1)Chart設定
     プロパティ設定 Seriseコレクション(ChartType:Line  XValueType:Time
 2)SerialPort設定
   
   
 3)コーディング コンストラクタ Form1(void)
   ①シリアルポートをOpenする。

 4)コーディング シリアルポート受信イベント処理 (serialPort1_DataReceived)
   ①Charting/Seriesオブジェクト series1tをローカル宣言
   ②DateTime型で現在時刻を取得する。
   ③シリアルポート受信データを取り込み、温度データを抽出する。
   ④取得した温度データでDataPointを作成し Series1に登録する。
         System::Windows:・・・:Charting::DataPoint^  tmppoint2
          = (gcnew System:・・・:Charting::DataPoint(timesp.ToOADate(),System::Convert::ToDouble(strvalue)));
      series1t->Points->Add(tmppoint2);
   ⑤Series1に登録されたDataPointオブジェクトが1024を超えた場合。先頭のDataPointオブジェクトを削除する。
      series1t->Points->RemoveAt(0);

===================================================================
※メモ
 ●DataPointの設定
 DateTime値をDataPointのX値に設定する場合 ToOADate()メソッドを使用する。
●チャートデータの更新処理の工夫
 データDataPointコレクションの更新時 Chatオブジェクトは非表示にする。 (前述)

※気になる点
●MicroSoftのmsdnオンラインドキュメントの不備
ChartクラスのSystem名前空間からの継承階層はSystem::Windows::Forms::DataVisualization::Charting::Chartですが、オンライドキュメントでSystem名前空間から繰るとSystem::Windows::Forms名前空間 止まりでした。また、DataVisualization名前空間配下の Series等のクラスではドキュメントの繰り方で、内容の無いページが現れます。
 とにかく、Chartクラスを使うのには情報が少ない。

0 件のコメント:

コメントを投稿