明星八卦
savefiledialog(C#上位机智能温湿度监控系统)

一、效果展示

启动界面

上位机采集

下位机模拟

导出excel

二、VS2022

.net4.8框架

Nuget安装NModbus

Nuget安装SQLite

Nuget安装NPOI

界面设计

三、代码展示

Form1.cs

using System;using System.Collections.Generic;using System.Data;using System.Drawing;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;using System.Windows.Forms.DataVisualization.Charting;namespace TempHumidityMonitor {    public partial class Form1 : Form {        private ModbusHelper _modbusHelper;        private System.Windows.Forms.Timer _readTimer;        private AppConfig _appConfig; // 存储当前配置        private const byte SLAVE_ID = 1; // Modbus从站地址        // --- 新增:用于报警管理 ---        private string _lastAlarmMessage = ""; // 记录上一次的报警内容,用于去重        private DateTime _lastAlarmTime = DateTime.MinValue;        public Form1() {            InitializeComponent();            InitializeUI();            SetupTimer();        }        private void InitializeUI() {            // 设置图表            chartData.Series.Clear();            var seriesTemp = chartData.Series.Add("温度");            seriesTemp.ChartType = SeriesChartType.Line;            seriesTemp.Color = Color.Red;            var seriesHumi = chartData.Series.Add("湿度");            seriesHumi.ChartType = SeriesChartType.Line;            seriesHumi.Color = Color.Blue;            var chartArea = chartData.ChartAreas[0];            chartArea.AxisX.LabelStyle.Format = "HH:mm:ss";            chartArea.AxisX.MajorGrid.Interval = 3;            chartArea.AxisX.MajorGrid.IntervalType = DateTimeIntervalType.Seconds;            chartArea.AxisX.LabelStyle.Interval = 3;            chartArea.AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Seconds;            chartArea.AxisY.Minimum = 0;            chartArea.AxisY.Maximum = 100;            chartArea.AxisY2.Enabled = AxisEnabled.True;            chartArea.AxisY2.Minimum = 0;            chartArea.AxisY2.Maximum = 100;            //chartArea.AxisX.ScaleView.Zoomable = true;            // 初始化状态标签            labelStatus.Text = "未连接";            labelStatus.ForeColor = Color.Red;            // 初始缩放大小设置为60秒(例如),可以根据需要调整            //chartArea.AxisX.ScaleView.Size = 10;            //chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Seconds;        }        private void SetupTimer() {            _readTimer = new System.Windows.Forms.Timer();            _readTimer.Interval = 2000; // 每2秒读取一次            _readTimer.Tick += ReadTimer_Tick;        }        private async void ReadTimer_Tick(object sender, EventArgs e) {            if (_modbusHelper == null || !_modbusHelper.IsConnected)                return;            try {                // 使用 Task.Run 并传入取消令牌                var result = await Task.Run(() => _modbusHelper.ReadData(SLAVE_ID));                if (result.HasValue) {                    float temp = result.Value.temperature;                    float humi = result.Value.humidity;                    // 更新UI                    UpdateDisplay(temp, humi);                    AddToChart(DateTime.Now, temp, humi);                    DatabaseHelper.SaveData(temp, humi);                    CheckAlarm(temp, humi);                }                else {                    SetStatus("读取数据失败", Color.Orange);                }            }            catch (Exception ex) {                this.Invoke((MethodInvoker)delegate {                    SetStatus($"读取异常: {ex.Message}", Color.Red);                });            }        }        private void UpdateDisplay(float temp, float humi) {            labelTemp.Text = $"{temp:F1} °C";            labelHumi.Text = $"{humi:F1} %";            SetStatus("连接正常", Color.Green);        }        private void AddToChart(DateTime time, float temp, float humi) {            // 添加数据点            chartData.Series["温度"].Points.AddXY(time, temp);            chartData.Series["湿度"].Points.AddXY(time, humi);            // 限制显示的数据点数量,防止图表过长            const int maxPoints = 10;            while (chartData.Series["温度"].Points.Count > maxPoints) {                chartData.Series["温度"].Points.RemoveAt(0);                chartData.Series["湿度"].Points.RemoveAt(0);            }            // 自动调整 X 轴范围            var chartArea = chartData.ChartAreas[0];            if (chartData.Series["温度"].Points.Count > 0) {                DateTime minTime = DateTime.FromOADate(chartData.Series["温度"].Points[0].XValue);                DateTime maxTime = time;                chartArea.AxisX.Minimum = minTime.ToOADate();                chartArea.AxisX.Maximum = maxTime.ToOADate();            }            chartData.Invalidate();        }        /// <summary>        /// 检查温湿度是否超出阈值,并更新UI和报警列表        /// </summary>        private void CheckAlarm(float temp, float humi) {            // 用于收集所有激活的报警            List<string> activeAlarms = new List<string>();            Color statusColor = Color.Green; // 默认正常颜色            // 获取当前阈值            float highTemp = (float)numericUpDownHighTemp.Value;            float lowTemp = (float)numericUpDownLowTemp.Value;            float highHumi = (float)numericUpDownHighHumi.Value;            float lowHumi = (float)numericUpDownLowHumi.Value;            // 检查温度            if (temp > highTemp) {                activeAlarms.Add($" 高温 {temp:F1}°C");                if (statusColor == Color.Green)                    statusColor = Color.Red; // 第一个非正常报警决定主色调            }            else if (temp < lowTemp) {                activeAlarms.Add($"❄️ 低温 {temp:F1}°C");                if (statusColor == Color.Green)                    statusColor = Color.Blue;            }            // 检查湿度            if (humi > highHumi) {                activeAlarms.Add($" 高湿 {humi:F1}%");                if (statusColor == Color.Green)                    statusColor = Color.Orange;            }            else if (humi < lowHumi) {                activeAlarms.Add($"️ 低湿 {humi:F1}%");                if (statusColor == Color.Green)                    statusColor = Color.Purple;            }            // --- 根据结果更新UI ---            if (activeAlarms.Count > 0) {                // 将所有报警信息用分号连接                string combinedMessage = string.Join("; ", activeAlarms);                // 更新状态栏                UpdateStatusStrip(combinedMessage, statusColor);                // 记录到报警列表(避免重复)                string logKey = string.Join("|", activeAlarms); // 用管道符连接作为唯一键                if (_lastAlarmMessage != logKey || (DateTime.Now - _lastAlarmTime).TotalSeconds > 60) {                    LogAlarm(combinedMessage);                    _lastAlarmMessage = logKey;                    _lastAlarmTime = DateTime.Now;                    //  可选:播放提示音                    if ((DateTime.Now - _lastAlarmTime).TotalSeconds > 300) {                        System.Media.SystemSounds.Exclamation.Play();                    }                }            }            else {                // 所有指标正常                UpdateStatusStrip("正常", Color.Green);                _lastAlarmMessage = "";            }        }        /// <summary>        /// 更新底部状态栏        /// </summary>        /// <param name="message">要显示的消息</param>        /// <param name="color">文本颜色</param>        private void UpdateStatusStrip(string message, Color color)        {            // ✅ 使用 Form (this) 来检查和调用            if (this.InvokeRequired)            {                // 如果在工作线程,需要通过 Invoke 切换到UI线程                this.Invoke((MethodInvoker)delegate {                    toolStripStatusLabel1.Text = message;                    toolStripStatusLabel1.ForeColor = color;                });            }            else            {                // 如果已经在UI线程,直接更新                toolStripStatusLabel1.Text = message;                toolStripStatusLabel1.ForeColor = color;            }        }        /// <summary>        /// 记录报警到ListBox        /// </summary>        /// <param name="message">报警消息</param>        private void LogAlarm(string message) {            string logEntry = $"[{DateTime.Now:HH:mm:ss}] {message}";            // ✅ 最佳实践:用 'this' 检查,用 listBoxAlarms.Invoke 执行            if (this.InvokeRequired) {                // 使用 listBoxAlarms 的 Invoke 方法将委托封送到UI线程                listBoxAlarms.Invoke((MethodInvoker)delegate {                    listBoxAlarms.Items.Add(logEntry);                    listBoxAlarms.TopIndex = listBoxAlarms.Items.Count - 1;                });            }            else {                // 直接在UI线程上操作                listBoxAlarms.Items.Add(logEntry);                listBoxAlarms.TopIndex = listBoxAlarms.Items.Count - 1;            }        }        private void SetStatus(string text, Color color) {            labelStatus.Text = text;            labelStatus.ForeColor = color;        }        // --- UI事件处理 ---        private void btnConnect_Click(object sender, EventArgs e) {            if (_modbusHelper?.IsConnected == true) {                _readTimer.Stop();                _modbusHelper?.Dispose();                _modbusHelper = null;                btnConnect.Text = "连接";                SetStatus("已断开", Color.Red);                return;            }            string portName = comboBoxPort.Text;            if (string.IsNullOrEmpty(portName)) {                MessageBox.Show("请选择串口号!");                return;            }            int baudRate = int.Parse(comboBoxBaudRate.Text);            _modbusHelper = new ModbusHelper();            if (_modbusHelper.Connect(portName, baudRate)) {                _readTimer.Start();                btnConnect.Text = "断开";                SetStatus("连接成功", Color.Green);            }            else {                MessageBox.Show("无法打开串口,请检查设备或端口设置。");                SetStatus("连接失败", Color.Red);            }        }        private void btnLoadHistory_Click(object sender, EventArgs e) {            DataTable data = DatabaseHelper.GetAllData();            dataGridViewHistory.DataSource = data;        }        private void Form1_Load(object sender, EventArgs e) {            // --- 加载配置 ---            _appConfig = JsonHelper.LoadConfig();            // 自动填充串口号            string[] ports = System.IO.Ports.SerialPort.GetPortNames();            comboBoxPort.Items.AddRange(ports);            if (!string.IsNullOrEmpty(_appConfig.PortName) && ports.Contains(_appConfig.PortName))            {                comboBoxPort.SelectedItem = _appConfig.PortName;            }            else if (ports.Length > 0)            {                comboBoxPort.SelectedIndex = 0; // 默认第一个            }            // 设置默认波特率            comboBoxBaudRate.Items.AddRange(new object[] { "9600", "19200", "38400", "57600", "115200" });            if (_appConfig.BaudRate.ToString() == comboBoxBaudRate.Items.Cast<string>().FirstOrDefault(x => x == _appConfig.BaudRate.ToString()))            {                comboBoxBaudRate.SelectedItem = _appConfig.BaudRate.ToString();            }            else            {                comboBoxBaudRate.SelectedItem = "115200"; // 默认            }            // 设置报警阈值            numericUpDownHighTemp.Value = (decimal)_appConfig.HighTemp;            numericUpDownLowTemp.Value = (decimal)_appConfig.LowTemp;            numericUpDownHighHumi.Value = (decimal)_appConfig.HighHumi;            numericUpDownLowHumi.Value = (decimal)_appConfig.LowHumi;        }        private void Form1_FormClosing(object sender, FormClosingEventArgs e)        {            _readTimer?.Stop();            // 直接调用 Disconnect,它会安全地清理所有资源            _modbusHelper?.Dispose();            _modbusHelper = null;            // --- 保存当前配置 ---            _appConfig.PortName = comboBoxPort.Text;            _appConfig.BaudRate = int.Parse(comboBoxBaudRate.Text);            _appConfig.HighTemp = (float)numericUpDownHighTemp.Value;            _appConfig.LowTemp = (float)numericUpDownLowTemp.Value;            _appConfig.HighHumi = (float)numericUpDownHighHumi.Value;            _appConfig.LowHumi = (float)numericUpDownLowHumi.Value;            JsonHelper.SaveConfig(_appConfig);        }        private void btnExport_Click(object sender, EventArgs e) {            // ✅ 直接从数据库获取所有数据,不依赖 DataGridView 的 DataSource            DataTable allData = DatabaseHelper.GetAllData();            if (allData == null || allData.Rows.Count == 0) {                MessageBox.Show("数据库中没有历史数据可导出。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);                return;            }            using (SaveFileDialog sfd = new SaveFileDialog()) {                sfd.Filter = "Excel文件|*.xlsx";                sfd.Title = "导出历史数据";                if (sfd.ShowDialog() == DialogResult.OK) {                    ExportToExcel(allData, sfd.FileName);                }            }        }        // 此方法现在只接收一个 DataTable,不再需要从 DataGridView 取数据        private void ExportToExcel(DataTable dt, string filePath) {            try {                NPOI.XSSF.UserModel.XSSFWorkbook workbook = new NPOI.XSSF.UserModel.XSSFWorkbook();                NPOI.SS.UserModel.ISheet sheet = workbook.CreateSheet("历史数据");                // 创建表头                NPOI.SS.UserModel.IRow headerRow = sheet.CreateRow(0);                for (int i = 0; i < dt.Columns.Count; i++) {                    headerRow.CreateCell(i).SetCellValue(dt.Columns[i].ColumnName);                }                // 填充数据                for (int i = 0; i < dt.Rows.Count; i++) {                    NPOI.SS.UserModel.IRow row = sheet.CreateRow(i + 1);                    for (int j = 0; j < dt.Columns.Count; j++) {                        row.CreateCell(j).SetCellValue(dt.Rows[i][j]?.ToString());                    }                }                // 自动调整列宽                for (int i = 0; i < dt.Columns.Count; i++) {                    sheet.AutoSizeColumn(i);                }                using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write)) {                    workbook.Write(fs);                }                MessageBox.Show("导出成功!");            }            catch (Exception ex) {                MessageBox.Show($"导出失败: {ex.Message}");            }        }    }}

Form1.Designer.cs

namespace TempHumidityMonitor {    partial class Form1 {        /// <summary>        /// 必需的设计器变量。        /// </summary>        private System.ComponentModel.IContainer components = null;        /// <summary>        /// 清理所有正在使用的资源。        /// </summary>        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>        protected override void Dispose(bool disposing) {            if (disposing && (components != null)) {                components.Dispose();            }            base.Dispose(disposing);        }        #region Windows 窗体设计器生成的代码        /// <summary>        /// 设计器支持所需的方法 - 不要修改        /// 使用代码编辑器修改此方法的内容。        /// </summary>        private void InitializeComponent() {            System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea2 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();            System.Windows.Forms.DataVisualization.Charting.Legend legend2 = new System.Windows.Forms.DataVisualization.Charting.Legend();            System.Windows.Forms.DataVisualization.Charting.Series series3 = new System.Windows.Forms.DataVisualization.Charting.Series();            System.Windows.Forms.DataVisualization.Charting.Series series4 = new System.Windows.Forms.DataVisualization.Charting.Series();            this.comboBoxPort = new System.Windows.Forms.ComboBox();            this.label1 = new System.Windows.Forms.Label();            this.label2 = new System.Windows.Forms.Label();            this.comboBoxBaudRate = new System.Windows.Forms.ComboBox();            this.btnConnect = new System.Windows.Forms.Button();            this.groupBox1 = new System.Windows.Forms.GroupBox();            this.labelTemp = new System.Windows.Forms.Label();            this.label4 = new System.Windows.Forms.Label();            this.label5 = new System.Windows.Forms.Label();            this.labelHumi = new System.Windows.Forms.Label();            this.label7 = new System.Windows.Forms.Label();            this.labelStatus = new System.Windows.Forms.Label();            this.chartData = new System.Windows.Forms.DataVisualization.Charting.Chart();            this.groupBox2 = new System.Windows.Forms.GroupBox();            this.numericUpDownLowHumi = new System.Windows.Forms.NumericUpDown();            this.numericUpDownHighHumi = new System.Windows.Forms.NumericUpDown();            this.numericUpDownLowTemp = new System.Windows.Forms.NumericUpDown();            this.numericUpDownHighTemp = new System.Windows.Forms.NumericUpDown();            this.label12 = new System.Windows.Forms.Label();            this.label11 = new System.Windows.Forms.Label();            this.label10 = new System.Windows.Forms.Label();            this.label9 = new System.Windows.Forms.Label();            this.label8 = new System.Windows.Forms.Label();            this.dataGridViewHistory = new System.Windows.Forms.DataGridView();            this.btnLoadHistory = new System.Windows.Forms.Button();            this.btnExport = new System.Windows.Forms.Button();            this.statusStrip1 = new System.Windows.Forms.StatusStrip();            this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();            this.listBoxAlarms = new System.Windows.Forms.ListBox();            this.groupBox1.SuspendLayout();            ((System.ComponentModel.ISupportInitialize)(this.chartData)).BeginInit();            this.groupBox2.SuspendLayout();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownLowHumi)).BeginInit();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownHighHumi)).BeginInit();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownLowTemp)).BeginInit();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownHighTemp)).BeginInit();            ((System.ComponentModel.ISupportInitialize)(this.dataGridViewHistory)).BeginInit();            this.statusStrip1.SuspendLayout();            this.SuspendLayout();            //             // comboBoxPort            //             this.comboBoxPort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;            this.comboBoxPort.FormattingEnabled = true;            this.comboBoxPort.Location = new System.Drawing.Point(65, 13);            this.comboBoxPort.Name = "comboBoxPort";            this.comboBoxPort.Size = new System.Drawing.Size(100, 24);            this.comboBoxPort.TabIndex = 0;            //             // label1            //             this.label1.AutoSize = true;            this.label1.Location = new System.Drawing.Point(12, 16);            this.label1.Name = "label1";            this.label1.Size = new System.Drawing.Size(43, 16);            this.label1.TabIndex = 1;            this.label1.Text = "串口号:";            //             // label2            //             this.label2.AutoSize = true;            this.label2.Location = new System.Drawing.Point(180, 16);            this.label2.Name = "label2";            this.label2.Size = new System.Drawing.Size(43, 16);            this.label2.TabIndex = 2;            this.label2.Text = "波特率:";            //             // comboBoxBaudRate            //             this.comboBoxBaudRate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;            this.comboBoxBaudRate.FormattingEnabled = true;            this.comboBoxBaudRate.Items.AddRange(new object[] {            "9600",            "19200",            "38400",            "57600",            "115200"});            this.comboBoxBaudRate.Location = new System.Drawing.Point(245, 13);            this.comboBoxBaudRate.Name = "comboBoxBaudRate";            this.comboBoxBaudRate.Size = new System.Drawing.Size(100, 24);            this.comboBoxBaudRate.TabIndex = 3;            //             // btnConnect            //             this.btnConnect.Location = new System.Drawing.Point(365, 11);            this.btnConnect.Name = "btnConnect";            this.btnConnect.Size = new System.Drawing.Size(80, 29);            this.btnConnect.TabIndex = 4;            this.btnConnect.Text = "连接";            this.btnConnect.UseVisualStyleBackColor = true;            this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);            //             // groupBox1            //             this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)             | System.Windows.Forms.AnchorStyles.Right)));            this.groupBox1.Controls.Add(this.labelTemp);            this.groupBox1.Controls.Add(this.label4);            this.groupBox1.Controls.Add(this.label5);            this.groupBox1.Controls.Add(this.labelHumi);            this.groupBox1.Controls.Add(this.label7);            this.groupBox1.Controls.Add(this.labelStatus);            this.groupBox1.Location = new System.Drawing.Point(12, 48);            this.groupBox1.Name = "groupBox1";            this.groupBox1.Size = new System.Drawing.Size(777, 64);            this.groupBox1.TabIndex = 5;            this.groupBox1.TabStop = false;            this.groupBox1.Text = "实时状态";            //             // labelTemp            //             this.labelTemp.AutoSize = true;            this.labelTemp.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.labelTemp.ForeColor = System.Drawing.Color.Red;            this.labelTemp.Location = new System.Drawing.Point(100, 27);            this.labelTemp.Name = "labelTemp";            this.labelTemp.Size = new System.Drawing.Size(66, 22);            this.labelTemp.TabIndex = 7;            this.labelTemp.Text = "--.-- °C";            //             // label4            //             this.label4.AutoSize = true;            this.label4.Location = new System.Drawing.Point(183, 32);            this.label4.Name = "label4";            this.label4.Size = new System.Drawing.Size(32, 16);            this.label4.TabIndex = 6;            this.label4.Text = "湿度:";            //             // label5            //             this.label5.AutoSize = true;            this.label5.Location = new System.Drawing.Point(6, 32);            this.label5.Name = "label5";            this.label5.Size = new System.Drawing.Size(32, 16);            this.label5.TabIndex = 5;            this.label5.Text = "温度:";            //             // labelHumi            //             this.labelHumi.AutoSize = true;            this.labelHumi.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.labelHumi.ForeColor = System.Drawing.Color.Blue;            this.labelHumi.Location = new System.Drawing.Point(228, 27);            this.labelHumi.Name = "labelHumi";            this.labelHumi.Size = new System.Drawing.Size(63, 22);            this.labelHumi.TabIndex = 8;            this.labelHumi.Text = "--.-- %";            //             // label7            //             this.label7.AutoSize = true;            this.label7.Location = new System.Drawing.Point(330, 32);            this.label7.Name = "label7";            this.label7.Size = new System.Drawing.Size(32, 16);            this.label7.TabIndex = 9;            this.label7.Text = "状态:";            //             // labelStatus            //             this.labelStatus.AutoSize = true;            this.labelStatus.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.labelStatus.Location = new System.Drawing.Point(375, 32);            this.labelStatus.Name = "labelStatus";            this.labelStatus.Size = new System.Drawing.Size(37, 20);            this.labelStatus.TabIndex = 10;            this.labelStatus.Text = "就绪";            //             // chartData            //             this.chartData.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)             | System.Windows.Forms.AnchorStyles.Left)             | System.Windows.Forms.AnchorStyles.Right)));            chartArea2.AxisX.LabelStyle.Format = "HH:mm:ss";            chartArea2.AxisX.MajorGrid.Interval = 5D;            chartArea2.AxisY.Title = "温度 (°C)";            chartArea2.AxisY2.Enabled = System.Windows.Forms.DataVisualization.Charting.AxisEnabled.True;            chartArea2.AxisY2.Title = "湿度 (%)";            chartArea2.Name = "ChartArea1";            this.chartData.ChartAreas.Add(chartArea2);            legend2.Name = "Legend1";            this.chartData.Legends.Add(legend2);            this.chartData.Location = new System.Drawing.Point(12, 118);            this.chartData.Name = "chartData";            series3.ChartArea = "ChartArea1";            series3.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;            series3.Legend = "Legend1";            series3.Name = "温度";            series4.ChartArea = "ChartArea1";            series4.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;            series4.Legend = "Legend1";            series4.Name = "湿度";            this.chartData.Series.Add(series3);            this.chartData.Series.Add(series4);            this.chartData.Size = new System.Drawing.Size(777, 310);            this.chartData.TabIndex = 6;            this.chartData.Text = "chart1";            //             // groupBox2            //             this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));            this.groupBox2.Controls.Add(this.numericUpDownLowHumi);            this.groupBox2.Controls.Add(this.numericUpDownHighHumi);            this.groupBox2.Controls.Add(this.numericUpDownLowTemp);            this.groupBox2.Controls.Add(this.numericUpDownHighTemp);            this.groupBox2.Controls.Add(this.label12);            this.groupBox2.Controls.Add(this.label11);            this.groupBox2.Controls.Add(this.label10);            this.groupBox2.Controls.Add(this.label9);            this.groupBox2.Controls.Add(this.label8);            this.groupBox2.Location = new System.Drawing.Point(12, 438);            this.groupBox2.Name = "groupBox2";            this.groupBox2.Size = new System.Drawing.Size(300, 160);            this.groupBox2.TabIndex = 7;            this.groupBox2.TabStop = false;            this.groupBox2.Text = "报警设置";            //             // numericUpDownLowHumi            //             this.numericUpDownLowHumi.DecimalPlaces = 1;            this.numericUpDownLowHumi.Increment = new decimal(new int[] {            5,            0,            0,            65536});            this.numericUpDownLowHumi.Location = new System.Drawing.Point(150, 117);            this.numericUpDownLowHumi.Name = "numericUpDownLowHumi";            this.numericUpDownLowHumi.Size = new System.Drawing.Size(80, 22);            this.numericUpDownLowHumi.TabIndex = 8;            this.numericUpDownLowHumi.Value = new decimal(new int[] {            30,            0,            0,            0});            //             // numericUpDownHighHumi            //             this.numericUpDownHighHumi.DecimalPlaces = 1;            this.numericUpDownHighHumi.Increment = new decimal(new int[] {            5,            0,            0,            65536});            this.numericUpDownHighHumi.Location = new System.Drawing.Point(150, 85);            this.numericUpDownHighHumi.Name = "numericUpDownHighHumi";            this.numericUpDownHighHumi.Size = new System.Drawing.Size(80, 22);            this.numericUpDownHighHumi.TabIndex = 7;            this.numericUpDownHighHumi.Value = new decimal(new int[] {            80,            0,            0,            0});            //             // numericUpDownLowTemp            //             this.numericUpDownLowTemp.DecimalPlaces = 1;            this.numericUpDownLowTemp.Increment = new decimal(new int[] {            5,            0,            0,            65536});            this.numericUpDownLowTemp.Location = new System.Drawing.Point(150, 53);            this.numericUpDownLowTemp.Minimum = new decimal(new int[] {            100,            0,            0,            -2147483648});            this.numericUpDownLowTemp.Name = "numericUpDownLowTemp";            this.numericUpDownLowTemp.Size = new System.Drawing.Size(80, 22);            this.numericUpDownLowTemp.TabIndex = 6;            this.numericUpDownLowTemp.Value = new decimal(new int[] {            10,            0,            0,            0});            //             // numericUpDownHighTemp            //             this.numericUpDownHighTemp.DecimalPlaces = 1;            this.numericUpDownHighTemp.Increment = new decimal(new int[] {            5,            0,            0,            65536});            this.numericUpDownHighTemp.Location = new System.Drawing.Point(150, 21);            this.numericUpDownHighTemp.Name = "numericUpDownHighTemp";            this.numericUpDownHighTemp.Size = new System.Drawing.Size(80, 22);            this.numericUpDownHighTemp.TabIndex = 5;            this.numericUpDownHighTemp.Value = new decimal(new int[] {            30,            0,            0,            0});            //             // label12            //             this.label12.AutoSize = true;            this.label12.Location = new System.Drawing.Point(80, 123);            this.label12.Name = "label12";            this.label12.Size = new System.Drawing.Size(54, 16);            this.label12.TabIndex = 4;            this.label12.Text = "低湿阈值:";            //             // label11            //             this.label11.AutoSize = true;            this.label11.Location = new System.Drawing.Point(80, 91);            this.label11.Name = "label11";            this.label11.Size = new System.Drawing.Size(54, 16);            this.label11.TabIndex = 3;            this.label11.Text = "高湿阈值:";            //             // label10            //             this.label10.AutoSize = true;            this.label10.Location = new System.Drawing.Point(80, 59);            this.label10.Name = "label10";            this.label10.Size = new System.Drawing.Size(54, 16);            this.label10.TabIndex = 2;            this.label10.Text = "低温阈值:";            //             // label9            //             this.label9.AutoSize = true;            this.label9.Location = new System.Drawing.Point(80, 27);            this.label9.Name = "label9";            this.label9.Size = new System.Drawing.Size(54, 16);            this.label9.TabIndex = 1;            this.label9.Text = "高温阈值:";            //             // label8            //             this.label8.AutoSize = true;            this.label8.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.label8.Location = new System.Drawing.Point(10, 27);            this.label8.Name = "label8";            this.label8.Size = new System.Drawing.Size(32, 17);            this.label8.TabIndex = 0;            this.label8.Text = "温度";            //             // dataGridViewHistory            //             this.dataGridViewHistory.AllowUserToAddRows = false;            this.dataGridViewHistory.AllowUserToDeleteRows = false;            this.dataGridViewHistory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)             | System.Windows.Forms.AnchorStyles.Right)));            this.dataGridViewHistory.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;            this.dataGridViewHistory.Location = new System.Drawing.Point(320, 434);            this.dataGridViewHistory.Name = "dataGridViewHistory";            this.dataGridViewHistory.Readonly = true;            this.dataGridViewHistory.RowTemplate.Height = 23;            this.dataGridViewHistory.Size = new System.Drawing.Size(469, 126);            this.dataGridViewHistory.TabIndex = 8;            //             // btnLoadHistory            //             this.btnLoadHistory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));            this.btnLoadHistory.Location = new System.Drawing.Point(406, 563);            this.btnLoadHistory.Name = "btnLoadHistory";            this.btnLoadHistory.Size = new System.Drawing.Size(100, 30);            this.btnLoadHistory.TabIndex = 9;            this.btnLoadHistory.Text = "加载历史数据";            this.btnLoadHistory.UseVisualStyleBackColor = true;            this.btnLoadHistory.Click += new System.EventHandler(this.btnLoadHistory_Click);            //             // btnExport            //             this.btnExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));            this.btnExport.Location = new System.Drawing.Point(584, 564);            this.btnExport.Name = "btnExport";            this.btnExport.Size = new System.Drawing.Size(100, 30);            this.btnExport.TabIndex = 10;            this.btnExport.Text = "导出Excel";            this.btnExport.UseVisualStyleBackColor = true;            this.btnExport.Click += new System.EventHandler(this.btnExport_Click);            //             // statusStrip1            //             this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {            this.toolStripStatusLabel1});            this.statusStrip1.Location = new System.Drawing.Point(0, 662);            this.statusStrip1.Name = "statusStrip1";            this.statusStrip1.Size = new System.Drawing.Size(801, 22);            this.statusStrip1.TabIndex = 11;            this.statusStrip1.Text = "statusStrip1";            //             // toolStripStatusLabel1            //             this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";            this.toolStripStatusLabel1.Size = new System.Drawing.Size(32, 17);            this.toolStripStatusLabel1.Text = "就绪";            //             // listBoxAlarms            //             this.listBoxAlarms.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)             | System.Windows.Forms.AnchorStyles.Right)));            this.listBoxAlarms.FormattingEnabled = true;            this.listBoxAlarms.ItemHeight = 16;            this.listBoxAlarms.Location = new System.Drawing.Point(320, 594);            this.listBoxAlarms.Name = "listBoxAlarms";            this.listBoxAlarms.Size = new System.Drawing.Size(469, 84);            this.listBoxAlarms.TabIndex = 12;            //             // Form1            //             this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 16F);            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;            this.ClientSize = new System.Drawing.Size(801, 684);            this.Controls.Add(this.listBoxAlarms);            this.Controls.Add(this.statusStrip1);            this.Controls.Add(this.btnExport);            this.Controls.Add(this.btnLoadHistory);            this.Controls.Add(this.dataGridViewHistory);            this.Controls.Add(this.chartData);            this.Controls.Add(this.groupBox2);            this.Controls.Add(this.groupBox1);            this.Controls.Add(this.btnConnect);            this.Controls.Add(this.comboBoxBaudRate);            this.Controls.Add(this.label2);            this.Controls.Add(this.label1);            this.Controls.Add(this.comboBoxPort);            this.Font = new System.Drawing.Font("微软雅黑", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.MinimumSize = new System.Drawing.Size(800, 680);            this.Name = "Form1";            this.Text = "智能温湿度监控系统";            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);            this.Load += new System.EventHandler(this.Form1_Load);            this.groupBox1.ResumeLayout(false);            this.groupBox1.PerformLayout();            ((System.ComponentModel.ISupportInitialize)(this.chartData)).EndInit();            this.groupBox2.ResumeLayout(false);            this.groupBox2.PerformLayout();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownLowHumi)).EndInit();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownHighHumi)).EndInit();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownLowTemp)).EndInit();            ((System.ComponentModel.ISupportInitialize)(this.numericUpDownHighTemp)).EndInit();            ((System.ComponentModel.ISupportInitialize)(this.dataGridViewHistory)).EndInit();            this.statusStrip1.ResumeLayout(false);            this.statusStrip1.PerformLayout();            this.ResumeLayout(false);            this.PerformLayout();        }        #endregion        private System.Windows.Forms.ComboBox comboBoxPort;        private System.Windows.Forms.Label label1;        private System.Windows.Forms.Label label2;        private System.Windows.Forms.ComboBox comboBoxBaudRate;        private System.Windows.Forms.Button btnConnect;        private System.Windows.Forms.GroupBox groupBox1;        private System.Windows.Forms.Label labelTemp;        private System.Windows.Forms.Label label4;        private System.Windows.Forms.Label label5;        private System.Windows.Forms.Label labelHumi;        private System.Windows.Forms.Label label7;        private System.Windows.Forms.Label labelStatus;        private System.Windows.Forms.DataVisualization.Charting.Chart chartData;        private System.Windows.Forms.GroupBox groupBox2;        private System.Windows.Forms.NumericUpDown numericUpDownLowHumi;        private System.Windows.Forms.NumericUpDown numericUpDownHighHumi;        private System.Windows.Forms.NumericUpDown numericUpDownLowTemp;        private System.Windows.Forms.NumericUpDown numericUpDownHighTemp;        private System.Windows.Forms.Label label12;        private System.Windows.Forms.Label label11;        private System.Windows.Forms.Label label10;        private System.Windows.Forms.Label label9;        private System.Windows.Forms.Label label8;        private System.Windows.Forms.DataGridView dataGridViewHistory;        private System.Windows.Forms.Button btnLoadHistory;        private System.Windows.Forms.Button btnExport;        private System.Windows.Forms.StatusStrip statusStrip1;        private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;        private System.Windows.Forms.ListBox listBoxAlarms;    }}

SqLiteHelper

using System;using System.Data.SQLite;namespace TempHumidityMonitor {    public static class DatabaseHelper {        private static string ConnectionString = "Data Source=sensor_data.db;Version=3;";        /// <summary>        /// 静态构造函数,在首次使用类时执行一次        /// </summary>        static DatabaseHelper() {            InitializeDatabase();        }        private static void InitializeDatabase() {            using (var connection = new SQLiteConnection(ConnectionString)) {                connection.Open();                string createTableSql = @"                    CREATE TABLE IF NOT EXISTS SensorData (                        Id INTEGER PRIMARY KEY AUTOINCREMENT,                        Temperature REAL NOT NULL,                        Humidity REAL NOT NULL,                        Timestamp DATETIME DEFAULT (datetime('now', 'localtime'))                    );";                using (var command = new SQLiteCommand(createTableSql, connection)) {                    command.ExecuteNonQuery();                }            }        }        /// <summary>        /// 保存一条数据到数据库        /// </summary>        public static void SaveData(float temperature, float humidity) {            using (var connection = new SQLiteConnection(ConnectionString)) {                connection.Open();                string insertSql = "INSERT INTO SensorData (Temperature, Humidity) VALUES (@temp, @humi)";                using (var command = new SQLiteCommand(insertSql, connection)) {                    command.Parameters.AddWithValue("@temp", temperature);                    command.Parameters.AddWithValue("@humi", humidity);                    command.ExecuteNonQuery();                }            }        }        /// <summary>        /// 查询所有历史数据        /// </summary>        /// <returns>包含历史数据的DataTable</returns>        public static System.Data.DataTable GetAllData() {            var dataTable = new System.Data.DataTable();            using (var connection = new SQLiteConnection(ConnectionString)) {                connection.Open();                string selectSql = "SELECT Id, Temperature, Humidity, Timestamp FROM SensorData ORDER BY Timestamp DESC";                using (var adapter = new SQLiteDataAdapter(selectSql, connection)) {                    adapter.Fill(dataTable);                }            }            return dataTable;        }    }}

导出Excel

// 此方法现在只接收一个 DataTable,不再需要从 DataGridView 取数据private void ExportToExcel(DataTable dt, string filePath) {try {		NPOI.XSSF.UserModel.XSSFWorkbook workbook = new NPOI.XSSF.UserModel.XSSFWorkbook();		NPOI.SS.UserModel.ISheet sheet = workbook.CreateSheet("历史数据");// 创建表头		NPOI.SS.UserModel.IRow headerRow = sheet.CreateRow(0);for (int i = 0; i < dt.Columns.Count; i++) {			headerRow.CreateCell(i).SetCellValue(dt.Columns[i].ColumnName);		}// 填充数据for (int i = 0; i < dt.Rows.Count; i++) {			NPOI.SS.UserModel.IRow row = sheet.CreateRow(i + 1);for (int j = 0; j < dt.Columns.Count; j++) {				row.CreateCell(j).SetCellValue(dt.Rows[i][j]?.ToString());			}		}// 自动调整列宽for (int i = 0; i < dt.Columns.Count; i++) {			sheet.AutoSizeColumn(i);		}		using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write)) {			workbook.Write(fs);		}		MessageBox.Show("导出成功!");	}catch (Exception ex) {		MessageBox.Show($"导出失败: {ex.Message}");	}}

Modbus通讯工具下载和测试

C# WinForm +Modbus RTU通讯


顶一下()     踩一下()

热门推荐

发表评论
0评