Files
NonWovenFabric/WindowsFormsApp6/Form3.cs

893 lines
31 KiB
C#
Raw Normal View History

2025-12-31 09:43:35 +08:00
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 Form3 : Form
{
2025-12-31 13:44:33 +08:00
#region
private const int TIMER_INTERVAL = 1000;
private const string DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
private const string ROW_WICKING_TIME = "吸水时间(s)";
private const string ROW_WICKING_HEIGHT = "吸芯高度(mm)";
private const string ROW_WICKING_RATE = "芯吸速率(mm/min)";
private const string ROW_AVG_WICKING_RATE = "平均芯吸速率(mm/min)";
private const string ROW_STD_DEVIATION = "标准偏差";
#endregion
#region
2025-12-31 09:43:35 +08:00
private System.Windows.Forms.Timer dataTimer;
2025-12-31 13:44:33 +08:00
private System.Windows.Forms.Timer clockTimer;
2025-12-31 09:43:35 +08:00
private DataTable sampleDataTable;
2025-12-31 13:44:33 +08:00
private int currentSampleCount = 5; // 当前试样数量,可动态调整
private readonly Random random = new Random();
#endregion
2025-12-31 09:43:35 +08:00
public Form3()
{
InitializeComponent();
InitializeDataTable();
InitializeTimer();
InitializeDataGridView();
InitializeEventHandlers();
}
/// <summary>
2025-12-31 13:44:33 +08:00
/// 设置试样数量1-20
2025-12-31 09:43:35 +08:00
/// </summary>
2025-12-31 13:44:33 +08:00
public void SetSampleCount(int count)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
if (count < 1 || count > 20)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
ShowMessage("试样数量必须在1-20之间", "参数错误", MessageBoxIcon.Warning);
return;
}
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
currentSampleCount = count;
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 重新初始化数据表和界面
sampleDataTable.Clear();
InitializeDataTable();
InitializeDataGridView();
UpdateDisplay();
}
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
/// <summary>
/// 初始化 DataGridView 列 - 实现2级表头
/// </summary>
private void InitializeDataGridView()
{
dataGridView1.SuspendLayout();
try
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = null;
dataGridView1.Columns.Clear();
// 移除可能存在的事件处理器
dataGridView1.CellFormatting -= DataGridView1_CellFormatting;
dataGridView1.CellValueChanged -= DataGridView1_CellValueChanged;
dataGridView1.CellBeginEdit -= DataGridView1_CellBeginEdit;
// 创建共享样式(不设置背景色,让 AlternatingRowsDefaultCellStyle 生效)
DataGridViewCellStyle centerStyle = new DataGridViewCellStyle
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
Alignment = DataGridViewContentAlignment.MiddleCenter
2025-12-31 09:43:35 +08:00
};
2025-12-31 13:44:33 +08:00
// 序号列
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
Name = "序号",
HeaderText = "序号",
DataPropertyName = "序号",
Width = 180,
ReadOnly = true,
DefaultCellStyle = centerStyle
});
// 为每个试样添加3列2级表头试样N + 子列1/2/3
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
Name = $"试样{i}_1",
HeaderText = $"试样{i}\n1",
DataPropertyName = $"试样{i}_1",
Width = 100,
ReadOnly = false,
DefaultCellStyle = (DataGridViewCellStyle)centerStyle.Clone()
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
Name = $"试样{i}_2",
HeaderText = $"试样{i}\n2",
DataPropertyName = $"试样{i}_2",
Width = 100,
ReadOnly = false,
DefaultCellStyle = (DataGridViewCellStyle)centerStyle.Clone()
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
Name = $"试样{i}_3",
HeaderText = $"试样{i}\n3",
DataPropertyName = $"试样{i}_3",
Width = 100,
ReadOnly = false,
DefaultCellStyle = (DataGridViewCellStyle)centerStyle.Clone()
});
}
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 绑定数据源
dataGridView1.DataSource = sampleDataTable;
dataGridView1.CellFormatting += DataGridView1_CellFormatting;
dataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
dataGridView1.CellBeginEdit += DataGridView1_CellBeginEdit;
}
finally
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
dataGridView1.ResumeLayout();
2025-12-31 09:43:35 +08:00
}
}
/// <summary>
/// 单元格编辑前事件 - 动态控制哪些单元格可以编辑
/// </summary>
private void DataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
2025-12-31 13:44:33 +08:00
if (e.RowIndex >= 0 && e.ColumnIndex > 0)
2025-12-31 09:43:35 +08:00
{
string rowName = dataGridView1.Rows[e.RowIndex].Cells["序号"].Value?.ToString() ?? "";
2025-12-31 13:44:33 +08:00
// 吸芯高度(mm)行 - 所有列都可以编辑
if (rowName == ROW_WICKING_HEIGHT)
2025-12-31 09:43:35 +08:00
{
return; // 允许编辑
}
// 其他行 - 取消编辑
e.Cancel = true;
}
}
/// <summary>
/// 单元格格式化事件 - 处理数值显示格式
/// </summary>
private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
2025-12-31 13:44:33 +08:00
if (e.RowIndex < 0 || e.ColumnIndex == 0) return; // 跳过序号列
// 格式化数值显示为2位小数
if (e.Value != null && e.Value != DBNull.Value)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
if (double.TryParse(e.Value.ToString(), out double numValue))
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
// 如果值为0或接近0显示为空白
if (Math.Abs(numValue) < 0.001)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
e.Value = "";
2025-12-31 09:43:35 +08:00
e.FormattingApplied = true;
2025-12-31 13:44:33 +08:00
return;
2025-12-31 09:43:35 +08:00
}
2025-12-31 13:44:33 +08:00
// 显示2位小数
e.Value = numValue.ToString("F2");
e.FormattingApplied = true;
2025-12-31 09:43:35 +08:00
}
}
2025-12-31 13:44:33 +08:00
else
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
// null 或 DBNull 显示为空白
e.Value = "";
e.FormattingApplied = true;
2025-12-31 09:43:35 +08:00
}
}
/// <summary>
/// 单元格值改变事件 - 手动输入后重新计算
/// </summary>
private void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
string rowName = dataGridView1.Rows[e.RowIndex].Cells["序号"].Value?.ToString() ?? "";
// 如果是吸芯高度行,任何列的修改都触发重新计算
2025-12-31 13:44:33 +08:00
if (rowName == ROW_WICKING_HEIGHT)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
CalculateAllRows();
RefreshDataGridView();
2025-12-31 09:43:35 +08:00
}
}
}
/// <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;
2025-12-31 13:44:33 +08:00
clockTimer = new System.Windows.Forms.Timer
{
Interval = TIMER_INTERVAL
};
clockTimer.Tick += (s, e) => label2.Text = DateTime.Now.ToString(DATE_TIME_FORMAT);
2025-12-31 09:43:35 +08:00
clockTimer.Start();
}
/// <summary>
/// 连接设备按钮点击事件
/// </summary>
private void Button1_Click(object sender, EventArgs e)
{
if (dataTimer.Enabled)
{
StopDataCollection();
2025-12-31 13:44:33 +08:00
UpdateButtonState(button1, "🔗 连接设备", Color.FromArgb(46, 204, 113));
ShowMessage("已停止数据采集");
2025-12-31 09:43:35 +08:00
}
else
{
StartDataCollection();
2025-12-31 13:44:33 +08:00
UpdateButtonState(button1, "⏸️ 停止采集", Color.FromArgb(231, 76, 60));
ShowMessage("开始数据采集");
2025-12-31 09:43:35 +08:00
}
}
/// <summary>
/// 打印按钮点击事件
/// </summary>
private void Button2_Click(object sender, EventArgs e)
{
2025-12-31 13:44:33 +08:00
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);
2025-12-31 09:43:35 +08:00
}
/// <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));
// 为每个试样添加3列试样次数1、2、3
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
sampleDataTable.Columns.Add($"试样{i}_1", typeof(double));
sampleDataTable.Columns.Add($"试样{i}_2", typeof(double));
sampleDataTable.Columns.Add($"试样{i}_3", typeof(double));
2025-12-31 09:43:35 +08:00
}
2025-12-31 13:44:33 +08:00
// 初始化5行数据
AddDataRow(ROW_WICKING_TIME);
AddDataRow(ROW_WICKING_HEIGHT);
AddDataRow(ROW_WICKING_RATE);
AddDataRow(ROW_AVG_WICKING_RATE);
AddDataRow(ROW_STD_DEVIATION);
2025-12-31 09:43:35 +08:00
}
/// <summary>
/// 添加数据行
/// </summary>
private void AddDataRow(string rowName)
{
DataRow row = sampleDataTable.NewRow();
row["序号"] = rowName;
// 初始化所有数值列为0
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
row[$"试样{i}_1"] = 0.0;
row[$"试样{i}_2"] = 0.0;
row[$"试样{i}_3"] = 0.0;
}
sampleDataTable.Rows.Add(row);
}
/// <summary>
/// 初始化定时器用于模拟寄存器数据读取
/// </summary>
private void InitializeTimer()
{
dataTimer = new System.Windows.Forms.Timer();
dataTimer.Interval = 1000; // 每秒读取一次
dataTimer.Tick += DataTimer_Tick;
}
/// <summary>
/// 定时器事件 - 模拟从寄存器读取吸水时间数据
/// </summary>
private void DataTimer_Tick(object sender, EventArgs e)
{
2025-12-31 13:44:33 +08:00
// 读取吸水时间(s) - 从寄存器读取
DataRow timeRow = sampleDataTable.Rows[0];
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
double registerValue = ReadRegisterData(i - 1);
timeRow[$"试样{i}_1"] = registerValue;
}
UpdateDisplay();
}
/// <summary>
/// 模拟从寄存器读取数据
/// </summary>
private double ReadRegisterData(int registerAddress)
{
return 30 + random.NextDouble() * 4;
}
/// <summary>
/// 生成模拟测试数据
/// </summary>
public void GenerateMockData()
{
2025-12-31 13:44:33 +08:00
// 清空所有行的数据(保持表结构)
foreach (DataRow row in sampleDataTable.Rows)
{
for (int i = 1; i <= currentSampleCount; i++)
{
row[$"试样{i}_1"] = 0.0;
row[$"试样{i}_2"] = 0.0;
row[$"试样{i}_3"] = 0.0;
}
}
2025-12-31 09:43:35 +08:00
// 第1行吸水时间s- 试样次数1系统读数
2025-12-31 13:44:33 +08:00
// 每个试样只在第1次测试时记录吸水时间
DataRow timeRow = sampleDataTable.Rows[0];
for (int i = 1; i <= currentSampleCount; i++)
{
double timeValue = Math.Round(30 + random.NextDouble() * 4, 2); // 30-34秒
timeRow[$"试样{i}_1"] = timeValue;
// 试样次数2和3不使用保持为0
}
// 第2行吸芯高度mm- 手动输入,不自动生成
// 保持为0等待用户手动输入
// 第3-5行芯吸速率、平均值、标准偏差 - 保持为0
// 等待用户输入吸芯高度后,会自动计算
// 更新显示
RefreshDataGridView();
ShowMessage($"已生成 {currentSampleCount} 个试样的吸水时间数据\n" +
$"- 吸水时间30-34秒系统读数\n" +
$"- 吸芯高度请手动输入每个试样3次测试\n" +
$"- 芯吸速率:输入吸芯高度后自动计算",
"模拟数据生成");
}
/// <summary>
/// 生成完整的测试数据(包含吸芯高度)- 用于快速测试
/// </summary>
public void GenerateFullMockData()
{
// 清空所有行的数据(保持表结构)
foreach (DataRow row in sampleDataTable.Rows)
{
for (int i = 1; i <= currentSampleCount; i++)
{
row[$"试样{i}_1"] = 0.0;
row[$"试样{i}_2"] = 0.0;
row[$"试样{i}_3"] = 0.0;
}
}
// 第1行吸水时间s
2025-12-31 09:43:35 +08:00
DataRow timeRow = sampleDataTable.Rows[0];
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
double timeValue = Math.Round(30 + random.NextDouble() * 4, 2);
timeRow[$"试样{i}_1"] = timeValue;
}
2025-12-31 13:44:33 +08:00
// 第2行吸芯高度mm- 生成测试数据
2025-12-31 09:43:35 +08:00
DataRow heightRow = sampleDataTable.Rows[1];
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
double baseHeight = 55 + random.NextDouble() * 10;
double height1 = Math.Round(baseHeight + (random.NextDouble() - 0.5) * 4, 2);
double height2 = Math.Round(baseHeight + (random.NextDouble() - 0.5) * 4, 2);
double height3 = Math.Round(baseHeight + (random.NextDouble() - 0.5) * 4, 2);
2025-12-31 09:43:35 +08:00
heightRow[$"试样{i}_1"] = height1;
heightRow[$"试样{i}_2"] = height2;
heightRow[$"试样{i}_3"] = height3;
}
// 计算所有行
CalculateAllRows();
// 更新显示
2025-12-31 13:44:33 +08:00
RefreshDataGridView();
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
ShowMessage($"已生成完整测试数据(包含吸芯高度)\n" +
$"- 吸水时间30-34秒\n" +
$"- 吸芯高度50-70mm自动生成\n" +
$"- 芯吸速率:已自动计算",
"完整测试数据");
2025-12-31 09:43:35 +08:00
}
/// <summary>
/// 更新界面显示
/// </summary>
private void UpdateDisplay()
{
2025-12-31 13:44:33 +08:00
RefreshDataGridView();
}
/// <summary>
/// 刷新DataGridView
/// </summary>
private void RefreshDataGridView()
{
if (dataGridView1.DataSource is DataTable dt)
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
dt.AcceptChanges();
2025-12-31 09:43:35 +08:00
dataGridView1.Refresh();
}
}
/// <summary>
/// 计算所有行的数据
/// </summary>
private void CalculateAllRows()
{
// 第3行芯吸速率mm/min= 吸芯高度 / (吸水时间 / 60)
CalculateWickingRate();
// 第4行平均芯吸速率mm/min
CalculateAverageWickingRate();
// 第5行标准偏差
CalculateStandardDeviation();
}
/// <summary>
/// 计算芯吸速率mm/min
/// 公式:芯吸速率 = 吸芯高度mm / (吸水时间s / 60)
/// </summary>
private void CalculateWickingRate()
{
DataRow timeRow = sampleDataTable.Rows[0]; // 吸水时间
DataRow heightRow = sampleDataTable.Rows[1]; // 吸芯高度
DataRow rateRow = sampleDataTable.Rows[2]; // 芯吸速率
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
// 获取吸水时间试样次数1系统读数
double time = ConvertToDouble(timeRow[$"试样{i}_1"]);
// 获取吸芯高度(优先使用对应列的数据)
// 试样次数1 → 使用吸芯高度_1
// 试样次数2 → 使用吸芯高度_2
// 试样次数3 → 使用吸芯高度_3
double height1 = ConvertToDouble(heightRow[$"试样{i}_1"]);
double height2 = ConvertToDouble(heightRow[$"试样{i}_2"]);
double height3 = ConvertToDouble(heightRow[$"试样{i}_3"]);
// 计算芯吸速率(使用对应的吸芯高度)
double rate = 0;
if (time > 0)
{
// 使用平均吸芯高度或选择非零值
double avgHeight = 0;
int count = 0;
if (height1 > 0) { avgHeight += height1; count++; }
if (height2 > 0) { avgHeight += height2; count++; }
if (height3 > 0) { avgHeight += height3; count++; }
if (count > 0)
{
avgHeight /= count;
rate = avgHeight / (time / 60.0);
}
}
// 存储到试样次数3系统计算
rateRow[$"试样{i}_3"] = Math.Round(rate, 2);
}
}
/// <summary>
/// 安全地将对象转换为double处理DBNull和null情况
/// </summary>
private double ConvertToDouble(object value)
{
if (value == null || value == DBNull.Value)
{
return 0.0;
}
if (double.TryParse(value.ToString(), out double result))
{
return result;
}
return 0.0;
}
/// <summary>
/// 计算平均芯吸速率mm/min
/// </summary>
private void CalculateAverageWickingRate()
{
DataRow rateRow = sampleDataTable.Rows[2]; // 芯吸速率
DataRow avgRow = sampleDataTable.Rows[3]; // 平均芯吸速率
List<double> rates = new List<double>();
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
double rate = ConvertToDouble(rateRow[$"试样{i}_3"]);
if (rate > 0)
{
rates.Add(rate);
}
}
double average = rates.Count > 0 ? rates.Average() : 0;
// 所有试样显示相同的平均值存储在试样次数3
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
avgRow[$"试样{i}_3"] = Math.Round(average, 2);
}
}
/// <summary>
/// 计算标准偏差
/// </summary>
private void CalculateStandardDeviation()
{
DataRow rateRow = sampleDataTable.Rows[2]; // 芯吸速率
DataRow stdRow = sampleDataTable.Rows[4]; // 标准偏差
List<double> rates = new List<double>();
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
double rate = ConvertToDouble(rateRow[$"试样{i}_3"]);
if (rate > 0)
{
rates.Add(rate);
}
}
double stdDev = 0;
if (rates.Count > 1)
{
double average = rates.Average();
double sumOfSquares = rates.Sum(r => Math.Pow(r - average, 2));
stdDev = Math.Sqrt(sumOfSquares / (rates.Count - 1));
}
// 所有试样显示相同的标准偏差存储在试样次数3
2025-12-31 13:44:33 +08:00
for (int i = 1; i <= currentSampleCount; i++)
2025-12-31 09:43:35 +08:00
{
stdRow[$"试样{i}_3"] = Math.Round(stdDev, 2);
}
}
/// <summary>
/// 启动数据采集
/// </summary>
public void StartDataCollection()
{
dataTimer.Start();
}
/// <summary>
/// 停止数据采集
/// </summary>
public void StopDataCollection()
{
dataTimer.Stop();
}
/// <summary>
/// 导出数据到 Excel (.xlsx)
/// </summary>
public void ExportToExcel(string filePath)
{
try
{
2025-12-31 13:44:33 +08:00
IWorkbook workbook = filePath.EndsWith(".xlsx")
? (IWorkbook)new XSSFWorkbook()
: new HSSFWorkbook();
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
ISheet sheet = workbook.CreateSheet("液体芯吸速率测试报表");
2025-12-31 09:43:35 +08:00
// 创建样式
2025-12-31 13:44:33 +08:00
var styles = CreateReportStyles(workbook);
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 创建表头2级
CreateReportHeader(sheet, styles.headerStyle);
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 填充数据
FillReportData(sheet, styles.dataStyle, styles.yellowStyle);
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 设置列宽
SetReportColumnWidths(sheet);
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 保存文件
SaveWorkbook(workbook, filePath);
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
ShowMessage($"数据已成功导出到:{filePath}", "导出成功");
}
catch (Exception ex)
{
ShowMessage($"导出失败:{ex.Message}", "错误", MessageBoxIcon.Error);
}
}
/// <summary>
/// 创建报表样式
/// </summary>
private (ICellStyle headerStyle, ICellStyle dataStyle, ICellStyle yellowStyle)
CreateReportStyles(IWorkbook workbook)
{
// 表头样式
ICellStyle headerStyle = workbook.CreateCellStyle();
headerStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
headerStyle.FillPattern = FillPattern.SolidForeground;
SetBorders(headerStyle);
headerStyle.Alignment = NPOIHorizontalAlignment.Center;
headerStyle.VerticalAlignment = VerticalAlignment.Center;
IFont headerFont = workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
// 白色背景样式
ICellStyle dataStyle = workbook.CreateCellStyle();
SetBorders(dataStyle);
dataStyle.Alignment = NPOIHorizontalAlignment.Center;
dataStyle.VerticalAlignment = VerticalAlignment.Center;
// 黄色背景样式
ICellStyle yellowStyle = workbook.CreateCellStyle();
yellowStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.LightYellow.Index;
yellowStyle.FillPattern = FillPattern.SolidForeground;
SetBorders(yellowStyle);
yellowStyle.Alignment = NPOIHorizontalAlignment.Center;
yellowStyle.VerticalAlignment = VerticalAlignment.Center;
return (headerStyle, dataStyle, yellowStyle);
}
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
/// <summary>
/// 设置单元格边框
/// </summary>
private void SetBorders(ICellStyle style)
{
style.BorderBottom = NPOIBorderStyle.Thin;
style.BorderTop = NPOIBorderStyle.Thin;
style.BorderLeft = NPOIBorderStyle.Thin;
style.BorderRight = NPOIBorderStyle.Thin;
}
/// <summary>
/// 创建报表表头2级
/// </summary>
private void CreateReportHeader(ISheet sheet, ICellStyle headerStyle)
{
// 创建第一行表头试样1-N
IRow headerRow1 = sheet.CreateRow(0);
headerRow1.Height = 400;
ICell cell0 = headerRow1.CreateCell(0);
cell0.SetCellValue("序号");
cell0.CellStyle = headerStyle;
sheet.AddMergedRegion(new CellRangeAddress(0, 1, 0, 0)); // 合并序号列
int colIndex = 1;
for (int i = 1; i <= currentSampleCount; i++)
{
ICell cell = headerRow1.CreateCell(colIndex);
cell.SetCellValue($"试样{i}");
cell.CellStyle = headerStyle;
sheet.AddMergedRegion(new CellRangeAddress(0, 0, colIndex, colIndex + 2));
colIndex += 3;
}
// 创建第二行表头试样次数1、2、3
IRow headerRow2 = sheet.CreateRow(1);
headerRow2.Height = 400;
colIndex = 1;
for (int i = 1; i <= currentSampleCount; i++)
{
ICell cell1 = headerRow2.CreateCell(colIndex++);
cell1.SetCellValue("1");
cell1.CellStyle = headerStyle;
ICell cell2 = headerRow2.CreateCell(colIndex++);
cell2.SetCellValue("2");
cell2.CellStyle = headerStyle;
ICell cell3 = headerRow2.CreateCell(colIndex++);
cell3.SetCellValue("3");
cell3.CellStyle = headerStyle;
}
}
/// <summary>
/// 填充报表数据
/// </summary>
private void FillReportData(ISheet sheet, ICellStyle dataStyle, ICellStyle yellowStyle)
{
int rowIndex = 2;
int dataRowIndex = 0;
foreach (DataRow dataRow in sampleDataTable.Rows)
{
IRow row = sheet.CreateRow(rowIndex);
row.Height = 380;
// 根据行索引选择样式(隔行变色)
ICellStyle rowStyle = (dataRowIndex % 2 == 0) ? dataStyle : yellowStyle;
// 序号列
ICell cellSeq = row.CreateCell(0);
cellSeq.SetCellValue(dataRow["序号"].ToString());
cellSeq.CellStyle = rowStyle;
int colIndex = 1;
for (int i = 1; i <= currentSampleCount; i++)
{
// 试样次数1
ICell cell1 = row.CreateCell(colIndex++);
double val1 = ConvertToDouble(dataRow[$"试样{i}_1"]);
if (Math.Abs(val1) >= 0.001) // 只有非0值才显示
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
cell1.SetCellValue(val1);
2025-12-31 09:43:35 +08:00
}
2025-12-31 13:44:33 +08:00
cell1.CellStyle = rowStyle;
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 试样次数2
ICell cell2 = row.CreateCell(colIndex++);
double val2 = ConvertToDouble(dataRow[$"试样{i}_2"]);
if (Math.Abs(val2) >= 0.001) // 只有非0值才显示
{
cell2.SetCellValue(val2);
}
cell2.CellStyle = rowStyle;
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
// 试样次数3
ICell cell3 = row.CreateCell(colIndex++);
double val3 = ConvertToDouble(dataRow[$"试样{i}_3"]);
if (Math.Abs(val3) >= 0.001) // 只有非0值才显示
{
cell3.SetCellValue(val3);
}
cell3.CellStyle = rowStyle;
2025-12-31 09:43:35 +08:00
}
2025-12-31 13:44:33 +08:00
rowIndex++;
dataRowIndex++;
}
}
2025-12-31 09:43:35 +08:00
2025-12-31 13:44:33 +08:00
/// <summary>
/// 设置报表列宽
/// </summary>
private void SetReportColumnWidths(ISheet sheet)
{
sheet.SetColumnWidth(0, 20 * 256); // 序号列
int totalColumns = currentSampleCount * 3;
for (int i = 1; i <= totalColumns; i++)
{
sheet.SetColumnWidth(i, 12 * 256); // 数据列
2025-12-31 09:43:35 +08:00
}
2025-12-31 13:44:33 +08:00
}
/// <summary>
/// 保存工作簿
/// </summary>
private void SaveWorkbook(IWorkbook workbook, string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
2025-12-31 09:43:35 +08:00
{
2025-12-31 13:44:33 +08:00
workbook.Write(fs);
2025-12-31 09:43:35 +08:00
}
}
/// <summary>
/// 生成报表(带格式的 Excel
/// </summary>
public void GenerateReport(string filePath)
{
// 使用 ExportToExcel 方法
ExportToExcel(filePath);
}
/// <summary>
/// 清空数据
/// </summary>
public void ClearData()
{
sampleDataTable.Clear();
InitializeDataTable();
2025-12-31 13:44:33 +08:00
RefreshDataGridView();
2025-12-31 09:43:35 +08:00
}
}
}