c# 从0实现一个温湿度监测的小工具 (14)

520 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

本章节继续进行界面的优化,主要包括以下几个部分:

  • 提取显示子类,优化实时数据显示
  • 优化曲线显示

先上效果图

image.png

修改实时数据界面

之前的实时数据显示方式通过treeview改变,本次优化为一个界面。可以选择显示模式
这样更加符合操作习惯。\

增加界面realdata

新增界面realdata,布局采用表格布局,放入一个按钮,一个panel
默认的显示方式是表格显示

image.png

修改datagride和dataline

修改两个界面,作为一个子窗口嵌入realdata窗口的panel中。

datagride

  1. 删除定时器相关代码
  2. 删除datatable初始化代码
  3. 删除界面toolbox -》formborderstyle设置为none
using System;
using System.Data;
using System.Windows.Forms;

namespace THSensor
{
    public partial class DataGride : Form
    {
        /// <summary>
        /// 数据缓存
        /// </summary>
        public DataTable DataBuffer = null;
        /// <summary>
        /// 构造
        /// </summary>
        public DataGride()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 刷新显示
        /// </summary>
        public void RefreshDisplay(DataTable data)
        { 
            DataBuffer = data;
            dataGridView1.Refresh();
        }
        /// <summary>
        /// 加载函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGride_Load(object sender, EventArgs e)
        {
            //自适应列宽
            dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
            //绑定数据到DataGridView
            dataGridView1.DataSource = DataBuffer;
            //不显示最后一个行
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.ReadOnly = true;
            //去除首列
            dataGridView1.RowHeadersVisible = false;
            dataGridView1.Columns["ID"].HeaderText = "序号";
            dataGridView1.Columns["温度"].HeaderText = "温度";
            dataGridView1.Columns["湿度"].HeaderText = "湿度";
            dataGridView1.Columns["时间"].HeaderText = "时间";
            //刷新
            dataGridView1.Refresh();
        }
    }
}

dataline

  1. 删除定时器相关代码
  2. 删除datatable初始化代码
  3. 删除界面toolbox -》formborderstyle设置为none
using ScottPlot;
using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;

namespace THSensor
{
    public partial class DataLine : Form
    {
        /// <summary>
        /// 数据缓存
        /// </summary>
        public DataTable DataBuffer = null;
        /// <summary>
        /// 构造
        /// </summary>
        public DataLine()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 初始化加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataLine_Load(object sender, EventArgs e)
        {
            //line
            formsPlot1.Plot.Style(Style.Seaborn);
            formsPlot1.Plot.Title("数据曲线");
            //不显示x轴
            formsPlot1.Plot.XAxis.Ticks(false);
            formsPlot1.Plot.XAxis.Line(false);
            formsPlot1.Plot.YAxis2.Line(false);
            formsPlot1.Plot.XAxis2.Line(false);
        }
        /// <summary>
        /// 刷新曲线
        /// </summary>
        public void RefreshDisplay(DataTable setdata)
        {
            try
            {
                DataBuffer = setdata;
                if (DataBuffer.Rows.Count < 1)
                    return;
                //清空
                formsPlot1.Plot.Clear();
                //温度
                string[] data = DataBuffer.AsEnumerable().Select(d => d.Field<string>("温度")).ToArray();
                double[] ys = Array.ConvertAll<string, double>(data, s => double.Parse(s));
                //湿度
                string[] data2 = DataBuffer.AsEnumerable().Select(d => d.Field<string>("湿度")).ToArray();
                double[] ys2 = Array.ConvertAll<string, double>(data2, s => double.Parse(s));
                formsPlot1.Plot.AddSignal(ys);
                formsPlot1.Plot.AddSignal(ys2);
                formsPlot1.Refresh();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + ex.StackTrace);
                MyLogger._.Error(ex.Message + "\r\n" + ex.StackTrace);
            }
        }
    }
}

realwin

  1. 实现定时器操作 定时器的操作和之前一样,主要实现数据的获取,入库,界面刷新
  2. 实现datatable初始化 初始化一个全局数据缓存datatable结构
  3. 实现刷新事件 定时器回调,根据当前的显示模式,选择刷新表格还是曲线
  4. 实现按钮切换回调 切换显示模式
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace THSensor
{
    public partial class RealDataWin : Form
    {
        /// <summary>
        /// 曲线模式
        /// </summary>
        private bool lineopend = false;
        /// <summary>
        /// 序号
        /// </summary>
        private int Index = 0;
        /// <summary>
        /// 数据缓存
        /// </summary>
        private DataTable DataBuffer;
        /// <summary>
        /// 曲线
        /// </summary>
        private DataLine datalinewin;
        /// <summary>
        /// 表格
        /// </summary>
        private DataGride datagridewin;
        /// <summary>
        /// 构造
        /// </summary>
        public RealDataWin()
        {
            InitializeComponent();
            InitDataTable();
        }
        /// <summary>
        /// 初始化结构
        /// </summary>
        private void InitDataTable()
        {
            DataBuffer = new DataTable();
            DataBuffer.Columns.Add("ID");
            DataBuffer.Columns.Add("温度");
            DataBuffer.Columns.Add("湿度");
            DataBuffer.Columns.Add("时间");
        }
        /// <summary>
        /// panel显示子窗口
        /// </summary>
        /// <param name="frm"></param>
        private void OpenWinToPanel(Form frm)
        {
            //取消非顶级窗体
            frm.TopLevel = false;
            frm.Width = this.panel1.Width;
            frm.Height = this.panel1.Height;
            frm.Dock = DockStyle.Fill;
            frm.Location = new Point(0, 0);
            //展示窗体
            frm.Show();
            this.panel1.Controls.Add(frm);
        }
        /// <summary>
        /// 表格模式
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            //打开
            if (!lineopend)
            {
                button1.Text = "表格模式";
                lineopend = true;
                //关闭表格窗体
                this.panel1.Controls.Remove(datagridewin);
                datagridewin.Close();
                //打开曲线窗体
                datalinewin = new DataLine();
                datalinewin.DataBuffer = this.DataBuffer;
                OpenWinToPanel(datalinewin);
            }
            else
            {
                button1.Text = "曲线模式";
                lineopend = false;
                this.panel1.Controls.Remove(datalinewin);
                datalinewin.Close();
                datagridewin = new DataGride();
                datagridewin.DataBuffer = this.DataBuffer;
                OpenWinToPanel(datagridewin);
            }
        }

        /// <summary>
        /// 定时器回调
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                if (Global.Runport.IsOpen)
                {
                    byte addr = 3;
                    if (Global.ComConfInfo.ContainsKey("devaddr"))
                        addr = byte.Parse(Global.ComConfInfo["devaddr"].ToString());
                    //获取数据
                    string ret = THSensor.ReadTHDataFromSensor(Global.Runport, addr);
                    if (!string.IsNullOrEmpty(ret))
                    {
                        string temp = ret.Split('&')[0];
                        string humi = ret.Split('&')[1];
                        //入库操作
                        DB_SerAPI.SaveTHData(temp, humi);
                        //刷新列表
                        string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        if (DataBuffer != null)
                        {
                            Index++;
                            DataRow row = DataBuffer.NewRow();
                            row["ID"] = Index.ToString();
                            row["时间"] = time;
                            row["温度"] = temp;
                            row["湿度"] = humi;
                            DataBuffer.Rows.Add(row);
                            if (!lineopend)
                                datagridewin.RefreshDisplay(DataBuffer);
                            else
                                datalinewin.RefreshDisplay(DataBuffer);
                        }
                    }
                    else
                    {
                        MessageBox.Show("无数据,请检查配置参数");
                    }
                }
            }
            catch (Exception ex)
            {
                MyLogger._.Error(ex.Message + "\r\n" + ex.StackTrace);
                MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 加载函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RealDataWin_Load(object sender, EventArgs e)
        {
            //默认表格
            button1.Text = "曲线模式";
            datagridewin = new DataGride();
            datagridewin.DataBuffer = this.DataBuffer;
            OpenWinToPanel(datagridewin);
            //启动定时器
            this.timer1.Start();
        }
    }
}

测试

曲线模式

image.png

表格模式

image.png

优化曲线显示

之前的曲线显示比较简单,坐标轴没有显示出来
y轴是自适应,看起来并不是很直观,下面我们对曲线进行优化
主要优化内容:

  • 增加坐标轴
  • 添加多Y轴显示
        /// <summary>
        /// 刷新曲线
        /// </summary>
        public void RefreshDisplay(DataTable setdata)
        {
            try
            {
                DataBuffer = setdata;
                if (DataBuffer.Rows.Count < 1)
                    return;
                //清空
                formsPlot1.Plot.Clear();
                formsPlot1.Reset();
                //温度
                string[] data = DataBuffer.AsEnumerable().Select(d => d.Field<string>("温度")).ToArray();
                double[] ys = Array.ConvertAll<string, double>(data, s => double.Parse(s));
                var temp = formsPlot1.Plot.AddSignal(ys);
                formsPlot1.Plot.YAxis.Color(temp.Color);
                formsPlot1.Plot.SetAxisLimits(yMin: -20, yMax: 80, yAxisIndex: 0);
                formsPlot1.Plot.YAxis.Label("温度");
                temp.YAxisIndex = 0;
                //湿度
                string[] data2 = DataBuffer.AsEnumerable().Select(d => d.Field<string>("湿度")).ToArray();
                double[] ys2 = Array.ConvertAll<string, double>(data2, s => double.Parse(s));
                var humi = formsPlot1.Plot.AddSignal(ys2);
                formsPlot1.Plot.YAxis2.Color(humi.Color);
                formsPlot1.Plot.SetAxisLimits(yMin:0,yMax:100,yAxisIndex:1);
                formsPlot1.Plot.YAxis2.Ticks(true); 
                formsPlot1.Plot.YAxis2.Label("湿度");
                humi.YAxisIndex = 1;
                //刷新
                formsPlot1.Refresh();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + ex.StackTrace);
                MyLogger._.Error(ex.Message + "\r\n" + ex.StackTrace);
            }
        }

测试

image.png