【C# WinForms】リアルタイム更新されるcsvデータをグラフ表示する

やりたいこと

別のアプリが一定時間ごとに更新しているcsvファイルがある

このcsvファイルをリアルタイムでグラフ表示

作ってみる

UI

button,chart,timer,openFileDialogを適当に配置

コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Windows.Forms.DataVisualization.Charting;

namespace chart_test1
{
    public partial class Form1 : Form
    {
        string file_name;
        FileStream stream;
        List<float> x_val;
        List<float> y_val;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //データ初期化
            {
                timer1.Stop();
                x_val = new List<float>();
                y_val = new List<float>();
                chart1.Series[0].Points.Clear();
            }

            //CSVファイル開く
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                file_name = openFileDialog1.FileName;

                Task task = Task.Run(() => { SubThred_GetNewData(); });

                timer1.Start();
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Task task = Task.Run(() => { SubThred_GetNewData(); });
        }

        private void SubThred_GetNewData()
        {
            List<DataPoint> points = new List<DataPoint>();

            using (stream = new FileStream(file_name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            using (var reader = new StreamReader(stream))
            {
                var len = 2;
                while (!reader.EndOfStream)
                {
                    var line = reader.ReadLine();
                    var values = line.Split(',');

                    if (values.Length >= len)
                    {
                        float x_tmp = float.Parse(values[0]);
                        float y_tmp = float.Parse(values[1]);

                        if (x_val.Contains(x_tmp))
                        {
                            //存在済みデータは無視
                        }
                        else
                        {
                            x_val.Add(x_tmp);
                            y_val.Add(y_tmp);
                            points.Add(new DataPoint(x_tmp, y_tmp));
                        }
                    }
                }
            }

            if ( points.Count > 0 )
            {
                this.Invoke(new Action<List<DataPoint>>(Chart_AddPoint), points);//delegateを実行
            }
        }

        private void Chart_AddPoint( List<DataPoint> points)
        {
            foreach ( DataPoint pt in points )
            {
                chart1.Series[0].Points.Add(pt);
            }
        }
    }
}

一定周期ごとにcsvファイルを先頭行から最終行までサーチして

増えたデータがあったらChartに追加してます。

増えた分だけを取得できるいい方法があればいいんですけどねー。知ってる方教えてください。

増えた分だけ取得するコードです

あとcsvファイルの更新をトリガにするのがよさそうですけどタイマで妥協しました。

動作

補足

一応上記動作確認に使ったcsvファイルに一定周期ごとに書き出すアプリのコードも載せときます。

1secごとにcsvファイルに出力してます。

1列目:t[sec],2列目:sin(30°×t)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public StreamWriter file;
        public long idx=0;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Task task1 = Task.Run(() => { SubThreadProcess(); });
        }

        private void SubThreadProcess()
        {
            file = new StreamWriter(@"test.csv", true, Encoding.UTF8);
            idx++;
            double rad = idx*30 * Math.PI / 180f;
            file.WriteLine(string.Format("{0},{1}", idx, Math.Sin(rad)));
            file.Close();
        }
    }
}

コメント

タイトルとURLをコピーしました