This commit is contained in:
GukSang.Jin
2025-12-31 13:44:33 +08:00
parent f00d3dd4dd
commit 5075aa0533
6 changed files with 1387 additions and 1227 deletions

View File

@@ -13,9 +13,17 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing && (components != null)) if (disposing)
{ {
components.Dispose(); if (components != null)
{
components.Dispose();
}
// 释放自定义资源
dataTimer?.Dispose();
clockTimer?.Dispose();
sampleDataTable?.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -13,9 +13,17 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing && (components != null)) if (disposing)
{ {
components.Dispose(); if (components != null)
{
components.Dispose();
}
// 释放自定义资源
dataTimer?.Dispose();
clockTimer?.Dispose();
sampleDataTable?.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }

View File

@@ -21,9 +21,26 @@ namespace WindowsFormsApp6
{ {
public partial class Form2 : Form public partial class Form2 : Form
{ {
#region
private const int TIMER_INTERVAL = 1000;
private const double MIN_WEIGHT = 10.0;
private const double MAX_WEIGHT = 20.0;
private const string DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
private const string ROW_INITIAL_WEIGHT = "初始重量(g)";
private const string ROW_AFTER_WEIGHT = "浸润后重量(g)";
private const string ROW_ABSORPTION = "液体吸收量(%)";
private const string ROW_AVG_ABSORPTION = "液体吸收量平均值(%)";
private const string ROW_MAX_ABSORPTION = "液体吸收量最大值(%)";
#endregion
#region
private System.Windows.Forms.Timer dataTimer; private System.Windows.Forms.Timer dataTimer;
private System.Windows.Forms.Timer clockTimer;
private DataTable sampleDataTable; private DataTable sampleDataTable;
private int sampleCount = 0; private int sampleCount = 0;
private int currentSampleCount = 5; // 当前试样数量,可动态调整
private readonly Random random = new Random();
#endregion
public Form2() public Form2()
{ {
@@ -39,136 +56,71 @@ namespace WindowsFormsApp6
/// </summary> /// </summary>
private void InitializeDataGridView() private void InitializeDataGridView()
{ {
// 清除现有列 dataGridView1.SuspendLayout();
dataGridView1.Columns.Clear(); try
// 添加新列以匹配 Excel 表格结构
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{ {
Name = "序号", dataGridView1.Columns.Clear();
HeaderText = "序号",
DataPropertyName = "序号",
Width = 150,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleCenter }
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn // 创建共享样式
{ var centerStyle = new DataGridViewCellStyle
Name = "试样1",
HeaderText = "试样1",
DataPropertyName = "试样1",
Width = 150,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle
{ {
Alignment = DataGridViewContentAlignment.MiddleCenter, Alignment = DataGridViewContentAlignment.MiddleCenter
BackColor = Color.FromArgb(255, 255, 200) // 黄色背景 };
}
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn var yellowCenterStyle = new DataGridViewCellStyle
{
Name = "试样2",
HeaderText = "试样2",
DataPropertyName = "试样2",
Width = 150,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle
{ {
Alignment = DataGridViewContentAlignment.MiddleCenter, Alignment = DataGridViewContentAlignment.MiddleCenter,
BackColor = Color.FromArgb(255, 255, 200) BackColor = Color.FromArgb(255, 255, 200)
} };
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn // 添加序号列
{ dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
Name = "试样3",
HeaderText = "试样3",
DataPropertyName = "试样3",
Width = 150,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle
{ {
Alignment = DataGridViewContentAlignment.MiddleCenter, Name = "序号",
BackColor = Color.FromArgb(255, 255, 200) HeaderText = "序号",
} DataPropertyName = "序号",
}); Width = 180,
ReadOnly = true,
DefaultCellStyle = centerStyle
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn // 根据当前试样数量动态添加列
{ for (int i = 1; i <= currentSampleCount; i++)
Name = "试样4",
HeaderText = "试样4",
DataPropertyName = "试样4",
Width = 150,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle
{ {
Alignment = DataGridViewContentAlignment.MiddleCenter, dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
BackColor = Color.FromArgb(255, 255, 200) {
Name = $"试样{i}",
HeaderText = $"试样{i}",
DataPropertyName = $"试样{i}",
Width = 150,
ReadOnly = true,
DefaultCellStyle = yellowCenterStyle
});
} }
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn // 绑定数据源
dataGridView1.DataSource = sampleDataTable;
dataGridView1.CellFormatting += DataGridView1_CellFormatting;
}
finally
{ {
Name = "试样5", dataGridView1.ResumeLayout();
HeaderText = "试样5", }
DataPropertyName = "试样5",
Width = 150,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle
{
Alignment = DataGridViewContentAlignment.MiddleCenter,
BackColor = Color.FromArgb(255, 255, 200)
}
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
Name = "时间",
HeaderText = "时间",
DataPropertyName = "时间",
Width = 200,
ReadOnly = true,
DefaultCellStyle = new DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleCenter }
});
// 绑定数据源
dataGridView1.DataSource = sampleDataTable;
// 添加单元格格式化事件
dataGridView1.CellFormatting += DataGridView1_CellFormatting;
} }
/// <summary> /// <summary>
/// 单元格格式化事件 - 处理平均值行的显示 /// 单元格格式化事件
/// </summary> /// </summary>
private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{ {
if (dataGridView1.Columns[e.ColumnIndex].Name == "时间" && e.RowIndex >= 0) if (e.RowIndex < 0) return;
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
if (row.Cells["序号"].Value != null && row.Cells["序号"].Value.ToString() == "平均时间(s)")
{
// 计算总平均值并显示
if (row.Cells["试样1"].Value != null)
{
double avg1 = Convert.ToDouble(row.Cells["试样1"].Value);
double avg2 = Convert.ToDouble(row.Cells["试样2"].Value);
double avg3 = Convert.ToDouble(row.Cells["试样3"].Value);
double avg4 = Convert.ToDouble(row.Cells["试样4"].Value);
double avg5 = Convert.ToDouble(row.Cells["试样5"].Value);
double overallAvg = (avg1 + avg2 + avg3 + avg4 + avg5) / 5;
e.Value = overallAvg.ToString("F2"); // 格式化数值显示为2位小数
e.FormattingApplied = true; if (e.Value != null && e.Value != DBNull.Value)
} {
} if (double.TryParse(e.Value.ToString(), out double numValue))
else if (e.Value != null && e.Value != DBNull.Value)
{ {
// 正常时间格式化 e.Value = numValue.ToString("F2");
DateTime dt = Convert.ToDateTime(e.Value);
e.Value = dt.ToString("yyyy-MM-dd HH:mm:ss");
e.FormattingApplied = true; e.FormattingApplied = true;
} }
} }
@@ -179,25 +131,17 @@ namespace WindowsFormsApp6
/// </summary> /// </summary>
private void InitializeEventHandlers() private void InitializeEventHandlers()
{ {
// 连接设备按钮
button1.Click += Button1_Click; button1.Click += Button1_Click;
// 打印按钮
button2.Click += Button2_Click; button2.Click += Button2_Click;
// 导出按钮
button3.Click += Button3_Click; button3.Click += Button3_Click;
// 返回按钮
button4.Click += Button4_Click; button4.Click += Button4_Click;
// 生成模拟数据按钮
button5.Click += Button5_Click; button5.Click += Button5_Click;
// 更新日期时间标签 clockTimer = new System.Windows.Forms.Timer
System.Windows.Forms.Timer clockTimer = new System.Windows.Forms.Timer(); {
clockTimer.Interval = 1000; Interval = TIMER_INTERVAL
clockTimer.Tick += (s, e) => label2.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); };
clockTimer.Tick += (s, e) => label2.Text = DateTime.Now.ToString(DATE_TIME_FORMAT);
clockTimer.Start(); clockTimer.Start();
} }
@@ -209,16 +153,14 @@ namespace WindowsFormsApp6
if (dataTimer.Enabled) if (dataTimer.Enabled)
{ {
StopDataCollection(); StopDataCollection();
button1.Text = "🔗 连接设备"; UpdateButtonState(button1, "🔗 连接设备", Color.FromArgb(46, 204, 113));
button1.BackColor = Color.FromArgb(46, 204, 113); ShowMessage("已停止数据采集");
MessageBox.Show("已停止数据采集", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
} }
else else
{ {
StartDataCollection(); StartDataCollection();
button1.Text = "⏸️ 停止采集"; UpdateButtonState(button1, "⏸️ 停止采集", Color.FromArgb(231, 76, 60));
button1.BackColor = Color.FromArgb(231, 76, 60); ShowMessage("开始数据采集");
MessageBox.Show("开始数据采集", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
} }
} }
@@ -227,7 +169,24 @@ namespace WindowsFormsApp6
/// </summary> /// </summary>
private void Button2_Click(object sender, EventArgs e) private void Button2_Click(object sender, EventArgs e)
{ {
MessageBox.Show("打印功能开发中...", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); 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>
@@ -271,12 +230,28 @@ namespace WindowsFormsApp6
{ {
sampleDataTable = new DataTable(); sampleDataTable = new DataTable();
sampleDataTable.Columns.Add("序号", typeof(string)); sampleDataTable.Columns.Add("序号", typeof(string));
sampleDataTable.Columns.Add("试样1", typeof(double));
sampleDataTable.Columns.Add("试样2", typeof(double)); // 根据当前试样数量动态添加列
sampleDataTable.Columns.Add("试样3", typeof(double)); for (int i = 1; i <= currentSampleCount; i++)
sampleDataTable.Columns.Add("试样4", typeof(double)); {
sampleDataTable.Columns.Add("试样5", typeof(double)); sampleDataTable.Columns.Add($"试样{i}", typeof(object));
sampleDataTable.Columns.Add("时间", typeof(DateTime)); }
}
/// <summary>
/// 设置试样数量并重新初始化
/// </summary>
public void SetSampleCount(int count)
{
if (count < 1 || count > 20) // 限制最大20个试样
{
ShowMessage("试样数量必须在1-20之间", "参数错误", MessageBoxIcon.Warning);
return;
}
currentSampleCount = count;
InitializeDataTable();
InitializeDataGridView();
} }
/// <summary> /// <summary>
@@ -284,8 +259,10 @@ namespace WindowsFormsApp6
/// </summary> /// </summary>
private void InitializeTimer() private void InitializeTimer()
{ {
dataTimer = new System.Windows.Forms.Timer(); dataTimer = new System.Windows.Forms.Timer
dataTimer.Interval = 1000; // 每秒读取一次 {
Interval = TIMER_INTERVAL
};
dataTimer.Tick += DataTimer_Tick; dataTimer.Tick += DataTimer_Tick;
} }
@@ -294,45 +271,48 @@ namespace WindowsFormsApp6
/// </summary> /// </summary>
private void DataTimer_Tick(object sender, EventArgs e) private void DataTimer_Tick(object sender, EventArgs e)
{ {
// 除旧的平均值行(如果存在) // 除旧的计算行
DataRow[] avgRows = sampleDataTable.Select("序号 = '平均时间(s)'"); RemoveCalculatedRows();
foreach (DataRow avgRow in avgRows)
// 读取初始重量和浸润后重量
double[] initialWeights = new double[currentSampleCount];
double[] afterWeights = new double[currentSampleCount];
for (int i = 0; i < currentSampleCount; i++)
{ {
sampleDataTable.Rows.Remove(avgRow); initialWeights[i] = ReadRegisterData(i * 2); // 初始重量
afterWeights[i] = ReadRegisterData(i * 2 + 1); // 浸润后重量
} }
// 模拟从寄存器读取数据(实际应用中替换为真实的寄存器读取代码)
double sample1 = ReadRegisterData(0); // 寄存器地址 0
double sample2 = ReadRegisterData(1); // 寄存器地址 1
double sample3 = ReadRegisterData(2); // 寄存器地址 2
double sample4 = ReadRegisterData(3); // 寄存器地址 3
double sample5 = ReadRegisterData(4); // 寄存器地址 4
// 添加到数据表
sampleCount++; sampleCount++;
DataRow dataRow = sampleDataTable.NewRow();
dataRow["序号"] = $"时间(s)"; // 更新显示
dataRow["试样1"] = sample1; UpdateDisplay(initialWeights, afterWeights);
dataRow["试样2"] = sample2; }
dataRow["试样3"] = sample3;
dataRow["试样4"] = sample4;
dataRow["试样5"] = sample5;
dataRow["时间"] = DateTime.Now;
sampleDataTable.Rows.Add(dataRow);
// 更新界面显示 /// <summary>
UpdateDisplay(); /// 移除计算行
/// </summary>
private void RemoveCalculatedRows()
{
var rowsToRemove = sampleDataTable.AsEnumerable()
.Where(r => r.Field<string>("序号") == ROW_ABSORPTION ||
r.Field<string>("序号") == ROW_AVG_ABSORPTION ||
r.Field<string>("序号") == ROW_MAX_ABSORPTION)
.ToList();
foreach (var row in rowsToRemove)
{
sampleDataTable.Rows.Remove(row);
}
} }
/// <summary> /// <summary>
/// 模拟从寄存器读取数据 /// 模拟从寄存器读取数据
/// 实际应用中替换为真实的 Modbus 或其他协议读取
/// </summary> /// </summary>
private double ReadRegisterData(int registerAddress) private double ReadRegisterData(int registerAddress)
{ {
// 模拟数据30-34 之间的随机值 return MIN_WEIGHT + random.NextDouble() * (MAX_WEIGHT - MIN_WEIGHT);
Random random = new Random(Guid.NewGuid().GetHashCode());
return 30 + random.NextDouble() * 4;
} }
/// <summary> /// <summary>
@@ -340,86 +320,125 @@ namespace WindowsFormsApp6
/// </summary> /// </summary>
public void GenerateMockData() public void GenerateMockData()
{ {
// 清空现有数据
sampleDataTable.Clear(); sampleDataTable.Clear();
sampleCount = 0; sampleCount = 0;
// 生成10条模拟数据 // 生成模拟数据
Random random = new Random(); double[] initialWeights = new double[currentSampleCount];
DateTime startTime = DateTime.Now.AddMinutes(-10); double[] afterWeights = new double[currentSampleCount];
for (int i = 0; i < 10; i++) for (int i = 0; i < currentSampleCount; i++)
{ {
DataRow dataRow = sampleDataTable.NewRow(); initialWeights[i] = Math.Round(MIN_WEIGHT + random.NextDouble() * (MAX_WEIGHT - MIN_WEIGHT), 2);
dataRow["序号"] = "时间(s)"; afterWeights[i] = Math.Round(initialWeights[i] * (1.2 + random.NextDouble() * 0.3), 2); // 浸润后增重20%-50%
// 为每个试样生成模拟数据30-34之间的随机值带小数点
dataRow["试样1"] = Math.Round(30 + random.NextDouble() * 4, 2);
dataRow["试样2"] = Math.Round(30 + random.NextDouble() * 4, 2);
dataRow["试样3"] = Math.Round(30 + random.NextDouble() * 4, 2);
dataRow["试样4"] = Math.Round(30 + random.NextDouble() * 4, 2);
dataRow["试样5"] = Math.Round(30 + random.NextDouble() * 4, 2);
// 时间递增
dataRow["时间"] = startTime.AddMinutes(i);
sampleDataTable.Rows.Add(dataRow);
sampleCount++;
} }
// 更新显示(包括平均值) sampleCount = 1;
UpdateDisplay(); UpdateDisplay(initialWeights, afterWeights);
MessageBox.Show($"已生成 {sampleCount} 模拟数据", "模拟数据生成", MessageBoxButtons.OK, MessageBoxIcon.Information); ShowMessage($"已生成 {currentSampleCount} 个试样的模拟数据", "模拟数据生成");
} }
/// <summary> /// <summary>
/// 更新界面显示 /// 更新界面显示
/// </summary> /// </summary>
private void UpdateDisplay() private void UpdateDisplay(double[] initialWeights, double[] afterWeights)
{ {
// 刷新 DataGridView sampleDataTable.Clear();
if (dataGridView1.DataSource != null)
int count = Math.Min(initialWeights.Length, currentSampleCount);
// 1. 初始重量行
DataRow initialRow = sampleDataTable.NewRow();
initialRow["序号"] = ROW_INITIAL_WEIGHT;
for (int i = 0; i < count; i++)
{ {
((DataTable)dataGridView1.DataSource).AcceptChanges(); initialRow[$"试样{i + 1}"] = initialWeights[i];
dataGridView1.Refresh();
} }
sampleDataTable.Rows.Add(initialRow);
// 计算平均时间并显示 // 2. 浸润后重量行
if (sampleDataTable.Rows.Count > 0) DataRow afterRow = sampleDataTable.NewRow();
afterRow["序号"] = ROW_AFTER_WEIGHT;
for (int i = 0; i < count; i++)
{ {
double avgSample1 = sampleDataTable.AsEnumerable().Average(r => r.Field<double>("试样1")); afterRow[$"试样{i + 1}"] = afterWeights[i];
double avgSample2 = sampleDataTable.AsEnumerable().Average(r => r.Field<double>("试样2")); }
double avgSample3 = sampleDataTable.AsEnumerable().Average(r => r.Field<double>("试样3")); sampleDataTable.Rows.Add(afterRow);
double avgSample4 = sampleDataTable.AsEnumerable().Average(r => r.Field<double>("试样4"));
double avgSample5 = sampleDataTable.AsEnumerable().Average(r => r.Field<double>("试样5"));
double overallAvg = (avgSample1 + avgSample2 + avgSample3 + avgSample4 + avgSample5) / 5; // 3. 液体吸收量行 (%)
DataRow absorptionRow = sampleDataTable.NewRow();
absorptionRow["序号"] = ROW_ABSORPTION;
double[] absorptions = new double[count];
for (int i = 0; i < count; i++)
{
absorptions[i] = ((afterWeights[i] - initialWeights[i]) / initialWeights[i]) * 100;
absorptionRow[$"试样{i + 1}"] = absorptions[i];
}
sampleDataTable.Rows.Add(absorptionRow);
// 添加平均值行到表格底部(如果还没有) // 4. 液体吸收量平均值行
DataRow[] avgRows = sampleDataTable.Select("序号 = '平均时间(s)'"); DataRow avgRow = sampleDataTable.NewRow();
if (avgRows.Length == 0) avgRow["序号"] = ROW_AVG_ABSORPTION;
{ double avgAbsorption = absorptions.Average();
DataRow avgRow = sampleDataTable.NewRow(); double stdDev = CalculateStandardDeviation(absorptions);
avgRow["序号"] = "平均时间(s)";
avgRow["试样1"] = avgSample1; // 第1列显示平均值
avgRow["试样2"] = avgSample2; avgRow["试样1"] = avgAbsorption;
avgRow["试样3"] = avgSample3;
avgRow["试样4"] = avgSample4; // 第2列显示标准偏差
avgRow["试样5"] = avgSample5; if (count >= 2)
// avgRow["时间"] = $"({overallAvg:F2}) 系统计算"; {
sampleDataTable.Rows.Add(avgRow); avgRow["试样2"] = stdDev;
} }
else
{ // 其他列为空
// 更新现有平均值行 for (int i = 3; i <= count; i++)
avgRows[0]["试样1"] = avgSample1; {
avgRows[0]["试样2"] = avgSample2; avgRow[$"试样{i}"] = DBNull.Value;
avgRows[0]["试样3"] = avgSample3; }
avgRows[0]["试样4"] = avgSample4; sampleDataTable.Rows.Add(avgRow);
avgRows[0]["试样5"] = avgSample5;
// avgRows[0]["时间"] = $"({overallAvg:F2}) 系统计算"; // 5. 液体吸收量最大值行
} DataRow maxRow = sampleDataTable.NewRow();
maxRow["序号"] = ROW_MAX_ABSORPTION;
double maxAbsorption = absorptions.Max();
// 第1列显示最大值
maxRow["试样1"] = maxAbsorption;
// 其他列为空
for (int i = 2; i <= count; i++)
{
maxRow[$"试样{i}"] = DBNull.Value;
}
sampleDataTable.Rows.Add(maxRow);
// 刷新界面
RefreshDataGridView();
}
/// <summary>
/// 计算标准偏差
/// </summary>
private double CalculateStandardDeviation(double[] values)
{
if (values.Length == 0) return 0;
double avg = values.Average();
double sumOfSquares = values.Sum(val => Math.Pow(val - avg, 2));
return Math.Sqrt(sumOfSquares / values.Length);
}
/// <summary>
/// 刷新DataGridView
/// </summary>
private void RefreshDataGridView()
{
if (dataGridView1.DataSource is DataTable dt)
{
dt.AcceptChanges();
dataGridView1.Refresh();
} }
} }
@@ -439,131 +458,6 @@ namespace WindowsFormsApp6
dataTimer.Stop(); dataTimer.Stop();
} }
/// <summary>
/// 导出数据到 Excel (.xlsx)
/// </summary>
public void ExportToExcel(string filePath)
{
try
{
IWorkbook workbook;
// 根据文件扩展名选择格式
if (filePath.EndsWith(".xlsx"))
{
workbook = new XSSFWorkbook(); // Excel 2007+
}
else
{
workbook = new HSSFWorkbook(); // Excel 97-2003
}
ISheet sheet = workbook.CreateSheet("液体吸收测试报表");
// 创建标题行
IRow headerRow = sheet.CreateRow(0);
headerRow.CreateCell(0).SetCellValue("序号");
headerRow.CreateCell(1).SetCellValue("试样1");
headerRow.CreateCell(2).SetCellValue("试样2");
headerRow.CreateCell(3).SetCellValue("试样3");
headerRow.CreateCell(4).SetCellValue("试样4");
headerRow.CreateCell(5).SetCellValue("试样5");
headerRow.CreateCell(6).SetCellValue("时间");
// 设置标题行样式
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);
for (int i = 0; i < 7; i++)
{
headerRow.GetCell(i).CellStyle = headerStyle;
}
// 填充数据
int rowIndex = 1;
foreach (DataRow dataRow in sampleDataTable.Rows)
{
// 跳过平均值行
if (dataRow["序号"].ToString() == "平均时间(s)")
continue;
IRow row = sheet.CreateRow(rowIndex);
row.CreateCell(0).SetCellValue(dataRow["序号"].ToString());
row.CreateCell(1).SetCellValue(Convert.ToDouble(dataRow["试样1"]));
row.CreateCell(2).SetCellValue(Convert.ToDouble(dataRow["试样2"]));
row.CreateCell(3).SetCellValue(Convert.ToDouble(dataRow["试样3"]));
row.CreateCell(4).SetCellValue(Convert.ToDouble(dataRow["试样4"]));
row.CreateCell(5).SetCellValue(Convert.ToDouble(dataRow["试样5"]));
// 处理时间列
if (dataRow["时间"] != DBNull.Value)
{
row.CreateCell(6).SetCellValue(Convert.ToDateTime(dataRow["时间"]).ToString("yyyy-MM-dd HH:mm:ss"));
}
rowIndex++;
}
// 添加平均值行
IRow avgRow = sheet.CreateRow(rowIndex);
avgRow.CreateCell(0).SetCellValue("平均时间(s)");
// 计算平均值(排除平均值行)
var dataRows = sampleDataTable.AsEnumerable().Where(r => r.Field<string>("序号") != "平均时间(s)");
double avgSample1 = dataRows.Average(r => r.Field<double>("试样1"));
double avgSample2 = dataRows.Average(r => r.Field<double>("试样2"));
double avgSample3 = dataRows.Average(r => r.Field<double>("试样3"));
double avgSample4 = dataRows.Average(r => r.Field<double>("试样4"));
double avgSample5 = dataRows.Average(r => r.Field<double>("试样5"));
double overallAvg = (avgSample1 + avgSample2 + avgSample3 + avgSample4 + avgSample5) / 5;
avgRow.CreateCell(1).SetCellValue(avgSample1);
avgRow.CreateCell(2).SetCellValue(avgSample2);
avgRow.CreateCell(3).SetCellValue(avgSample3);
avgRow.CreateCell(4).SetCellValue(avgSample4);
avgRow.CreateCell(5).SetCellValue(avgSample5);
// 显示总平均值
ICell avgCell = avgRow.CreateCell(6);
avgCell.SetCellValue(overallAvg.ToString("F2"));
// 设置平均值行样式
ICellStyle avgStyle = workbook.CreateCellStyle();
avgStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
avgStyle.FillPattern = FillPattern.SolidForeground;
for (int i = 0; i < 7; i++)
{
if (avgRow.GetCell(i) != null)
{
avgRow.GetCell(i).CellStyle = avgStyle;
}
}
// 自动调整列宽
for (int i = 0; i < 7; i++)
{
sheet.AutoSizeColumn(i);
}
// 保存文件
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(fs);
}
MessageBox.Show($"数据已成功导出到:{filePath}", "导出成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"导出失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary> /// <summary>
/// 生成报表(带格式的 Excel /// 生成报表(带格式的 Excel
/// </summary> /// </summary>
@@ -575,109 +469,173 @@ namespace WindowsFormsApp6
ISheet sheet = workbook.CreateSheet("液体吸收测试报表"); ISheet sheet = workbook.CreateSheet("液体吸收测试报表");
// 创建样式 // 创建样式
ICellStyle titleStyle = workbook.CreateCellStyle(); var styles = CreateReportStyles(workbook);
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; CreateReportTitle(sheet, styles.titleStyle);
headerStyle.FillPattern = FillPattern.SolidForeground;
headerStyle.BorderBottom = NPOIBorderStyle.Thin;
headerStyle.BorderTop = NPOIBorderStyle.Thin;
headerStyle.BorderLeft = NPOIBorderStyle.Thin;
headerStyle.BorderRight = NPOIBorderStyle.Thin;
IFont headerFont = workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
headerStyle.Alignment = NPOIHorizontalAlignment.Center;
ICellStyle dataStyle = workbook.CreateCellStyle(); // 创建表头
dataStyle.BorderBottom = NPOIBorderStyle.Thin; CreateReportHeader(sheet, styles.headerStyle);
dataStyle.BorderTop = NPOIBorderStyle.Thin;
dataStyle.BorderLeft = NPOIBorderStyle.Thin;
dataStyle.BorderRight = NPOIBorderStyle.Thin;
dataStyle.Alignment = NPOIHorizontalAlignment.Center;
// 标题 // 填充数据
IRow titleRow = sheet.CreateRow(0); FillReportData(sheet, styles.dataStyle, styles.yellowStyle);
ICell titleCell = titleRow.CreateCell(0);
titleCell.SetCellValue("液体吸收测试报表");
titleCell.CellStyle = titleStyle;
sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, 6));
// 表头
IRow headerRow = sheet.CreateRow(2);
string[] headers = { "序号", "试样1", "试样2", "试样3", "试样4", "试样5", "根据标准" };
for (int i = 0; i < headers.Length; i++)
{
ICell cell = headerRow.CreateCell(i);
cell.SetCellValue(headers[i]);
cell.CellStyle = headerStyle;
}
// 数据行
int rowIndex = 3;
IRow timeRow = sheet.CreateRow(rowIndex++);
timeRow.CreateCell(0).SetCellValue("时间(s)");
timeRow.GetCell(0).CellStyle = dataStyle;
for (int i = 1; i <= 5; i++)
{
double value = 29 + i; // 示例数据30, 31, 32, 33, 34
ICell cell = timeRow.CreateCell(i);
cell.SetCellValue(value);
cell.CellStyle = dataStyle;
// 黄色背景
ICellStyle yellowStyle = workbook.CreateCellStyle();
yellowStyle.CloneStyleFrom(dataStyle);
yellowStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
yellowStyle.FillPattern = FillPattern.SolidForeground;
cell.CellStyle = yellowStyle;
}
ICell standardCell = timeRow.CreateCell(6);
standardCell.CellStyle = dataStyle;
// 平均时间行
IRow avgRow = sheet.CreateRow(rowIndex);
avgRow.CreateCell(0).SetCellValue("平均时间(s)");
avgRow.GetCell(0).CellStyle = dataStyle;
ICell avgCell = avgRow.CreateCell(1);
avgCell.SetCellValue("32");
avgCell.CellStyle = dataStyle;
// 黄色背景
ICellStyle avgYellowStyle = workbook.CreateCellStyle();
avgYellowStyle.CloneStyleFrom(dataStyle);
avgYellowStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Yellow.Index;
avgYellowStyle.FillPattern = FillPattern.SolidForeground;
avgCell.CellStyle = avgYellowStyle;
sheet.AddMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 1, 5));
// 设置列宽 // 设置列宽
sheet.SetColumnWidth(0, 20 * 256); SetReportColumnWidths(sheet);
for (int i = 1; i <= 6; i++)
{
sheet.SetColumnWidth(i, 15 * 256);
}
// 保存文件 // 保存文件
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) SaveWorkbook(workbook, filePath);
{
workbook.Write(fs);
}
MessageBox.Show($"报表已成功生成:{filePath}", "生成成功", MessageBoxButtons.OK, MessageBoxIcon.Information); ShowMessage($"报表已成功生成:{filePath}", "生成成功");
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show($"生成报表失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 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 FillReportData(ISheet sheet, ICellStyle dataStyle, ICellStyle yellowStyle)
{
int rowIndex = 3;
foreach (DataRow dataRow in sampleDataTable.Rows)
{
IRow row = sheet.CreateRow(rowIndex++);
string rowName = dataRow["序号"].ToString();
// 序号列
ICell nameCell = row.CreateCell(0);
nameCell.SetCellValue(rowName);
nameCell.CellStyle = dataStyle;
// 数据列
for (int i = 1; i <= currentSampleCount; i++)
{
ICell cell = row.CreateCell(i);
var value = dataRow[$"试样{i}"];
if (value != null && value != DBNull.Value)
{
if (double.TryParse(value.ToString(), out double numValue))
{
cell.SetCellValue(numValue);
}
else
{
cell.SetCellValue(value.ToString());
}
}
cell.CellStyle = yellowStyle;
}
}
}
/// <summary>
/// 设置报表列宽
/// </summary>
private void SetReportColumnWidths(ISheet sheet)
{
sheet.SetColumnWidth(0, 25 * 256);
for (int i = 1; i <= currentSampleCount; i++)
{
sheet.SetColumnWidth(i, 18 * 256);
}
}
/// <summary>
/// 保存工作簿
/// </summary>
private void SaveWorkbook(IWorkbook workbook, string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(fs);
} }
} }
@@ -688,7 +646,7 @@ namespace WindowsFormsApp6
{ {
sampleDataTable.Clear(); sampleDataTable.Clear();
sampleCount = 0; sampleCount = 0;
UpdateDisplay(); RefreshDataGridView();
} }
} }
} }

View File

@@ -13,9 +13,34 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing && (components != null)) if (disposing)
{ {
components.Dispose(); if (components != null)
{
components.Dispose();
}
// 释放定时器资源
if (clockTimer != null)
{
clockTimer.Stop();
clockTimer.Dispose();
clockTimer = null;
}
if (dataTimer != null)
{
dataTimer.Stop();
dataTimer.Dispose();
dataTimer = null;
}
// 释放数据表资源
if (sampleDataTable != null)
{
sampleDataTable.Dispose();
sampleDataTable = null;
}
} }
base.Dispose(disposing); base.Dispose(disposing);
} }

File diff suppressed because it is too large Load Diff