Files
NonWovenFabric/WindowsFormsApp6/Form1.cs
GukSang.Jin c84fb2f480 更新
2026-01-03 11:11:22 +08:00

841 lines
27 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 NPOI.SS.UserModel;
using NPOI.XSSF.UserModel; // 用于 .xlsx
using NPOI.HSSF.UserModel; // 用于 .xls
using NPOI.SS.Util;
// 使用别名解决命名空间冲突
using NPOIBorderStyle = NPOI.SS.UserModel.BorderStyle;
using NPOIHorizontalAlignment = NPOI.SS.UserModel.HorizontalAlignment;
namespace WindowsFormsApp6
{
public partial class Form1 : Form
{
#region
private const int TIMER_INTERVAL = 1000;
private const double MIN_SAMPLE_VALUE = 30.0;
private const double MAX_SAMPLE_VALUE = 34.0;
private const int COLUMN_WIDTH_STANDARD = 150;
private const int COLUMN_WIDTH_TIME = 200;
private const string AVG_ROW_LABEL = "平均时间(s)";
private const string TIME_ROW_LABEL = "时间(s)";
private const string DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
#endregion
#region
private System.Windows.Forms.Timer dataTimer;
private System.Windows.Forms.Timer clockTimer;
private DataTable sampleDataTable;
private int sampleCount = 0;
private int currentSampleCount = 5; // 当前试样数量,可动态调整
private readonly Random random = new Random();
#endregion
public Form1()
{
InitializeComponent();
InitializeDataTable();
InitializeTimer();
InitializeDataGridView();
InitializeEventHandlers();
}
/// <summary>
/// 初始化 DataGridView 列
/// </summary>
private void InitializeDataGridView()
{
dataGridView1.SuspendLayout();
try
{
dataGridView1.Columns.Clear();
// 创建共享样式
var centerAlignStyle = new DataGridViewCellStyle
{
Alignment = DataGridViewContentAlignment.MiddleCenter
};
var yellowCenterStyle = new DataGridViewCellStyle
{
Alignment = DataGridViewContentAlignment.MiddleCenter,
BackColor = Color.FromArgb(255, 255, 200)
};
// 添加序号列
AddColumn("序号", "序号", COLUMN_WIDTH_STANDARD, centerAlignStyle);
// 添加试样列
for (int i = 1; i <= currentSampleCount; i++)
{
AddColumn($"试样{i}", $"试样{i}", COLUMN_WIDTH_STANDARD, yellowCenterStyle);
}
// 绑定数据源
dataGridView1.DataSource = sampleDataTable;
dataGridView1.CellFormatting += DataGridView1_CellFormatting;
}
finally
{
dataGridView1.ResumeLayout();
}
}
/// <summary>
/// 添加列的辅助方法
/// </summary>
private void AddColumn(string name, string headerText, int width, DataGridViewCellStyle style)
{
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
Name = name,
HeaderText = headerText,
DataPropertyName = name,
Width = width,
ReadOnly = true,
DefaultCellStyle = style
});
}
/// <summary>
/// 单元格格式化事件 - 处理平均值行的显示
/// </summary>
private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.RowIndex < 0) return;
// 格式化数值显示为2位小数
if (e.Value != null && e.Value != DBNull.Value)
{
if (double.TryParse(e.Value.ToString(), out double numValue))
{
e.Value = numValue.ToString("F2");
e.FormattingApplied = true;
}
}
}
/// <summary>
/// 尝试计算总平均值
/// </summary>
private bool TryCalculateOverallAverage(DataGridViewRow row, out double overallAvg)
{
overallAvg = 0;
try
{
double sum = 0;
for (int i = 1; i <= currentSampleCount; i++)
{
var cellValue = row.Cells[$"试样{i}"].Value;
if (cellValue == null) return false;
sum += Convert.ToDouble(cellValue);
}
overallAvg = sum / currentSampleCount;
return true;
}
catch
{
return false;
}
}
// 移除TryCalculateOverallAverage方法因为不再需要
/// <summary>
/// 初始化事件处理器
/// </summary>
private void InitializeEventHandlers()
{
button1.Click += Button1_Click;
button2.Click += Button2_Click;
button3.Click += Button3_Click;
button4.Click += Button4_Click;
button5.Click += Button5_Click;
// 初始化时钟定时器
clockTimer = new System.Windows.Forms.Timer
{
Interval = TIMER_INTERVAL
};
clockTimer.Tick += (s, e) => label2.Text = DateTime.Now.ToString(DATE_TIME_FORMAT);
clockTimer.Start();
}
/// <summary>
/// 连接设备按钮点击事件
/// </summary>
private void Button1_Click(object sender, EventArgs e)
{
if (dataTimer.Enabled)
{
StopDataCollection();
UpdateButtonState(button1, "🔗 连接设备", Color.FromArgb(46, 204, 113));
ShowMessage("已停止数据采集");
}
else
{
StartDataCollection();
UpdateButtonState(button1, "⏸️ 停止采集", Color.FromArgb(231, 76, 60));
ShowMessage("开始数据采集");
}
}
/// <summary>
/// 更新按钮状态
/// </summary>
private void UpdateButtonState(Button button, string text, Color backColor)
{
button.Text = text;
button.BackColor = backColor;
}
/// <summary>
/// 显示提示消息
/// </summary>
private void ShowMessage(string message, string title = "提示", MessageBoxIcon icon = MessageBoxIcon.Information)
{
MessageBox.Show(message, title, MessageBoxButtons.OK, icon);
}
/// <summary>
/// 打印按钮点击事件
/// </summary>
private void Button2_Click(object sender, EventArgs e)
{
ShowMessage("打印功能开发中...");
}
/// <summary>
/// 导出按钮点击事件
/// </summary>
private void Button3_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Excel 文件 (*.xlsx)|*.xlsx|Excel 97-2003 (*.xls)|*.xls",
FileName = $"液体吸收测试报告_{DateTime.Now:yyyyMMdd_HHmmss}",
Title = "导出数据"
};
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
GenerateReport(saveFileDialog.FileName);
}
}
/// <summary>
/// 返回按钮点击事件
/// </summary>
private void Button4_Click(object sender, EventArgs e)
{
this.Close();
}
/// <summary>
/// 生成模拟数据按钮点击事件
/// </summary>
private void Button5_Click(object sender, EventArgs e)
{
GenerateMockData();
}
/// <summary>
/// 初始化数据表结构
/// </summary>
private void InitializeDataTable()
{
sampleDataTable = new DataTable();
sampleDataTable.Columns.Add("序号", typeof(string));
for (int i = 1; i <= currentSampleCount; i++)
{
sampleDataTable.Columns.Add($"试样{i}", typeof(double));
}
}
/// <summary>
/// 设置试样数量并重新初始化
/// </summary>
public void SetSampleCount(int count)
{
if (count < 1 || count > 20)
{
ShowMessage("试样数量必须在1-20之间", "参数错误", MessageBoxIcon.Warning);
return;
}
currentSampleCount = count;
InitializeDataTable();
InitializeDataGridView();
}
/// <summary>
/// 初始化定时器用于模拟寄存器数据读取
/// </summary>
private void InitializeTimer()
{
dataTimer = new System.Windows.Forms.Timer
{
Interval = TIMER_INTERVAL
};
dataTimer.Tick += DataTimer_Tick;
}
/// <summary>
/// 定时器事件 - 模拟从寄存器读取数据
/// </summary>
private void DataTimer_Tick(object sender, EventArgs e)
{
// 移除旧的平均值行
RemoveAverageRows();
// 创建新数据行
DataRow dataRow = sampleDataTable.NewRow();
dataRow["序号"] = TIME_ROW_LABEL;
// 读取寄存器数据
for (int i = 0; i < currentSampleCount; i++)
{
dataRow[$"试样{i + 1}"] = ReadRegisterData(i);
}
// 不再设置时间列
sampleDataTable.Rows.Add(dataRow);
sampleCount++;
UpdateDisplay();
}
/// <summary>
/// 移除平均值行
/// </summary>
private void RemoveAverageRows()
{
var avgRows = sampleDataTable.Select($"序号 = '{AVG_ROW_LABEL}'");
foreach (var row in avgRows)
{
sampleDataTable.Rows.Remove(row);
}
}
/// <summary>
/// 模拟从寄存器读取数据
/// 实际应用中替换为真实的 Modbus 或其他协议读取
/// </summary>
private double ReadRegisterData(int registerAddress)
{
// 模拟数据30-34 之间的随机值
return MIN_SAMPLE_VALUE + random.NextDouble() * (MAX_SAMPLE_VALUE - MIN_SAMPLE_VALUE);
}
/// <summary>
/// 生成模拟测试数据
/// </summary>
public void GenerateMockData()
{
sampleDataTable.Clear();
sampleCount = 0;
const int mockDataCount = 1;
for (int i = 0; i < mockDataCount; i++)
{
DataRow dataRow = sampleDataTable.NewRow();
dataRow["序号"] = TIME_ROW_LABEL;
// 为每个试样生成模拟数据
for (int j = 1; j <= currentSampleCount; j++)
{
double value = MIN_SAMPLE_VALUE + random.NextDouble() * (MAX_SAMPLE_VALUE - MIN_SAMPLE_VALUE);
dataRow[$"试样{j}"] = Math.Round(value, 2);
}
// 不再设置时间列
sampleDataTable.Rows.Add(dataRow);
sampleCount++;
}
UpdateDisplay();
ShowMessage($"已生成 {sampleCount} 条模拟数据", "模拟数据生成");
}
/// <summary>
/// 更新界面显示
/// </summary>
private void UpdateDisplay()
{
if (sampleDataTable.Rows.Count == 0)
return;
// 计算并添加/更新平均值行
UpdateAverageRow(null);
// 刷新界面
RefreshDataGridView();
}
/// <summary>
/// 计算所有试样的总平均值
/// </summary>
private double CalculateOverallAverage()
{
var timeRows = sampleDataTable.AsEnumerable()
.Where(r => r.Field<string>("序号") == TIME_ROW_LABEL);
if (!timeRows.Any())
return 0;
double sum = 0;
int count = 0;
foreach (var row in timeRows)
{
for (int i = 1; i <= currentSampleCount; i++)
{
sum += row.Field<double>($"试样{i}");
count++;
}
}
return count > 0 ? sum / count : 0;
}
/// <summary>
/// 更新或添加平均值行
/// </summary>
private void UpdateAverageRow(double[] averages)
{
var avgRows = sampleDataTable.Select($"序号 = '{AVG_ROW_LABEL}'");
// 计算总平均值
double overallAvg = CalculateOverallAverage();
if (avgRows.Length == 0)
{
// 添加新的平均值行
DataRow avgRow = sampleDataTable.NewRow();
avgRow["序号"] = AVG_ROW_LABEL;
// 只在第一列显示总平均值
avgRow["试样1"] = overallAvg;
// 其他列设置为空
for (int i = 2; i <= currentSampleCount; i++)
{
avgRow[$"试样{i}"] = DBNull.Value;
}
sampleDataTable.Rows.Add(avgRow);
}
else
{
// 更新现有平均值行
avgRows[0]["试样1"] = overallAvg;
// 其他列设置为空
for (int i = 2; i <= currentSampleCount; i++)
{
avgRows[0][$"试样{i}"] = DBNull.Value;
}
}
}
/// <summary>
/// 刷新DataGridView
/// </summary>
private void RefreshDataGridView()
{
if (dataGridView1.DataSource is DataTable dt)
{
dt.AcceptChanges();
dataGridView1.Refresh();
}
}
/// <summary>
/// 启动数据采集
/// </summary>
public void StartDataCollection()
{
dataTimer.Start();
}
/// <summary>
/// 停止数据采集
/// </summary>
public void StopDataCollection()
{
dataTimer.Stop();
}
/// <summary>
/// 导出数据到 Excel (.xlsx)
/// </summary>
public void ExportToExcel(string filePath)
{
try
{
IWorkbook workbook = CreateWorkbook(filePath);
ISheet sheet = workbook.CreateSheet("液体吸收测试报表");
// 创建样式
var styles = CreateExcelStyles(workbook);
// 创建标题行
CreateHeaderRow(sheet, styles.headerStyle);
// 填充数据
FillDataRows(sheet, styles.dataStyle);
// 添加平均值行
AddAverageRow(sheet, styles.avgStyle);
// 自动调整列宽
AutoSizeColumns(sheet, 7);
// 保存文件
SaveWorkbook(workbook, filePath);
ShowMessage($"数据已成功导出到:{filePath}", "导出成功");
}
catch (Exception ex)
{
ShowMessage($"导出失败:{ex.Message}", "错误", MessageBoxIcon.Error);
}
}
/// <summary>
/// 创建工作簿
/// </summary>
private IWorkbook CreateWorkbook(string filePath)
{
return filePath.EndsWith(".xlsx")
? (IWorkbook)new XSSFWorkbook()
: new HSSFWorkbook();
}
/// <summary>
/// 创建Excel样式
/// </summary>
private (ICellStyle headerStyle, ICellStyle dataStyle, ICellStyle avgStyle) CreateExcelStyles(IWorkbook workbook)
{
// 标题样式
ICellStyle headerStyle = workbook.CreateCellStyle();
headerStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
headerStyle.FillPattern = FillPattern.SolidForeground;
IFont headerFont = workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
// 数据样式
ICellStyle dataStyle = workbook.CreateCellStyle();
// 平均值样式
ICellStyle avgStyle = workbook.CreateCellStyle();
avgStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
avgStyle.FillPattern = FillPattern.SolidForeground;
return (headerStyle, dataStyle, avgStyle);
}
/// <summary>
/// 创建标题行
/// </summary>
private void CreateHeaderRow(ISheet sheet, ICellStyle headerStyle)
{
IRow headerRow = sheet.CreateRow(0);
// 序号列
ICell cell0 = headerRow.CreateCell(0);
cell0.SetCellValue("序号");
cell0.CellStyle = headerStyle;
// 动态创建试样列
for (int i = 1; i <= currentSampleCount; i++)
{
ICell cell = headerRow.CreateCell(i);
cell.SetCellValue($"试样{i}");
cell.CellStyle = headerStyle;
}
}
/// <summary>
/// 填充数据行
/// </summary>
private void FillDataRows(ISheet sheet, ICellStyle dataStyle)
{
int rowIndex = 1;
foreach (DataRow dataRow in sampleDataTable.Rows)
{
if (dataRow["序号"].ToString() == AVG_ROW_LABEL)
continue;
IRow row = sheet.CreateRow(rowIndex++);
row.CreateCell(0).SetCellValue(dataRow["序号"].ToString());
for (int i = 1; i <= currentSampleCount; i++)
{
row.CreateCell(i).SetCellValue(Convert.ToDouble(dataRow[$"试样{i}"]));
}
}
}
/// <summary>
/// 添加平均值行
/// </summary>
private void AddAverageRow(ISheet sheet, ICellStyle avgStyle)
{
var dataRows = sampleDataTable.AsEnumerable()
.Where(r => r.Field<string>("序号") != AVG_ROW_LABEL);
if (!dataRows.Any())
return;
int rowIndex = sheet.LastRowNum + 1;
IRow avgRow = sheet.CreateRow(rowIndex);
// 序号列
ICell labelCell = avgRow.CreateCell(0);
labelCell.SetCellValue(AVG_ROW_LABEL);
labelCell.CellStyle = avgStyle;
// 计算总平均值
double overallAvg = CalculateOverallAverage();
// 在第一个试样列显示总平均值
ICell avgCell = avgRow.CreateCell(1);
avgCell.SetCellValue(overallAvg);
avgCell.CellStyle = avgStyle;
// 合并所有试样列
if (currentSampleCount > 1)
{
sheet.AddMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 1, currentSampleCount));
}
}
/// <summary>
/// 自动调整列宽
/// </summary>
private void AutoSizeColumns(ISheet sheet, int columnCount)
{
for (int i = 0; i <= currentSampleCount; i++)
{
sheet.AutoSizeColumn(i);
}
}
/// <summary>
/// 保存工作簿
/// </summary>
private void SaveWorkbook(IWorkbook workbook, string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(fs);
}
}
/// <summary>
/// 生成报表(带格式的 Excel
/// </summary>
public void GenerateReport(string filePath)
{
try
{
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet = workbook.CreateSheet("液体吸收测试报表");
// 创建样式
var styles = CreateReportStyles(workbook);
// 创建标题
CreateReportTitle(sheet, styles.titleStyle);
// 创建表头
CreateReportHeader(sheet, styles.headerStyle);
// 创建数据行
CreateReportDataRows(sheet, styles.dataStyle, styles.yellowStyle);
// 设置列宽
SetReportColumnWidths(sheet);
// 保存文件
SaveWorkbook(workbook, filePath);
ShowMessage($"报表已成功生成:{filePath}", "生成成功");
}
catch (Exception ex)
{
ShowMessage($"生成报表失败:{ex.Message}", "错误", MessageBoxIcon.Error);
}
}
/// <summary>
/// 创建报表样式
/// </summary>
private (ICellStyle titleStyle, ICellStyle headerStyle, ICellStyle dataStyle, ICellStyle yellowStyle)
CreateReportStyles(IWorkbook workbook)
{
// 标题样式
ICellStyle titleStyle = workbook.CreateCellStyle();
IFont titleFont = workbook.CreateFont();
titleFont.FontHeightInPoints = 16;
titleFont.IsBold = true;
titleStyle.SetFont(titleFont);
titleStyle.Alignment = NPOIHorizontalAlignment.Center;
// 表头样式
ICellStyle headerStyle = workbook.CreateCellStyle();
headerStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
headerStyle.FillPattern = FillPattern.SolidForeground;
SetBorders(headerStyle);
IFont headerFont = workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
headerStyle.Alignment = NPOIHorizontalAlignment.Center;
// 数据样式
ICellStyle dataStyle = workbook.CreateCellStyle();
SetBorders(dataStyle);
dataStyle.Alignment = NPOIHorizontalAlignment.Center;
// 黄色背景样式
ICellStyle yellowStyle = workbook.CreateCellStyle();
yellowStyle.CloneStyleFrom(dataStyle);
yellowStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
yellowStyle.FillPattern = FillPattern.SolidForeground;
return (titleStyle, headerStyle, dataStyle, yellowStyle);
}
/// <summary>
/// 设置单元格边框
/// </summary>
private void SetBorders(ICellStyle style)
{
style.BorderBottom = NPOIBorderStyle.Thin;
style.BorderTop = NPOIBorderStyle.Thin;
style.BorderLeft = NPOIBorderStyle.Thin;
style.BorderRight = NPOIBorderStyle.Thin;
}
/// <summary>
/// 创建报表标题
/// </summary>
private void CreateReportTitle(ISheet sheet, ICellStyle titleStyle)
{
IRow titleRow = sheet.CreateRow(0);
ICell titleCell = titleRow.CreateCell(0);
titleCell.SetCellValue("液体吸收测试报表");
titleCell.CellStyle = titleStyle;
sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, currentSampleCount));
}
/// <summary>
/// 创建报表表头
/// </summary>
private void CreateReportHeader(ISheet sheet, ICellStyle headerStyle)
{
IRow headerRow = sheet.CreateRow(2);
// 序号列
ICell cell0 = headerRow.CreateCell(0);
cell0.SetCellValue("序号");
cell0.CellStyle = headerStyle;
// 动态创建试样列
for (int i = 1; i <= currentSampleCount; i++)
{
ICell cell = headerRow.CreateCell(i);
cell.SetCellValue($"试样{i}");
cell.CellStyle = headerStyle;
}
// 不再添加"根据标准"列
}
/// <summary>
/// 创建报表数据行
/// </summary>
private void CreateReportDataRows(ISheet sheet, ICellStyle dataStyle, ICellStyle yellowStyle)
{
int rowIndex = 3;
// 从数据表中获取时间行数据
var timeRows = sampleDataTable.AsEnumerable()
.Where(r => r.Field<string>("序号") == TIME_ROW_LABEL);
if (timeRows.Any())
{
foreach (var dataRow in timeRows)
{
IRow timeRow = sheet.CreateRow(rowIndex++);
ICell labelCell = timeRow.CreateCell(0);
labelCell.SetCellValue(TIME_ROW_LABEL);
labelCell.CellStyle = dataStyle;
for (int i = 1; i <= currentSampleCount; i++)
{
ICell cell = timeRow.CreateCell(i);
cell.SetCellValue(dataRow.Field<double>($"试样{i}"));
cell.CellStyle = yellowStyle;
}
}
}
// 平均时间行
IRow avgRow = sheet.CreateRow(rowIndex);
ICell avgLabelCell = avgRow.CreateCell(0);
avgLabelCell.SetCellValue(AVG_ROW_LABEL);
avgLabelCell.CellStyle = dataStyle;
// 计算并显示总平均值
double overallAvg = CalculateOverallAverage();
ICell avgCell = avgRow.CreateCell(1);
avgCell.SetCellValue(overallAvg);
avgCell.CellStyle = yellowStyle;
// 合并所有试样列
if (currentSampleCount > 1)
{
sheet.AddMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 1, currentSampleCount));
}
}
/// <summary>
/// 设置报表列宽
/// </summary>
private void SetReportColumnWidths(ISheet sheet)
{
sheet.SetColumnWidth(0, 20 * 256);
for (int i = 1; i <= currentSampleCount; i++)
{
sheet.SetColumnWidth(i, 15 * 256);
}
}
/// <summary>
/// 清空数据
/// </summary>
public void ClearData()
{
sampleDataTable.Clear();
sampleCount = 0;
UpdateDisplay();
}
}
}