Files
JoyD/Windows/CS/Framework4.0/Toprie/Toprie/Setting.cs

2230 lines
95 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.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace JoyD.Windows.CS
{
public partial class Setting : Form
{
// 创建并显示检测配置窗口
public static Setting Form = new Setting();
// 定时器字段
private Timer _timer;
// 绘制模式标志
private bool _isDrawingMode = false;
// 温差图绘制模式标志
private bool _isTempDiffDrawingMode = false;
// 矩形绘制相关变量
private Point _startPoint;
private Rectangle _currentRectangle = Rectangle.Empty;
private bool _isDrawing = false;
private List<RegionInfo> _drawnRectangles = new List<RegionInfo>();
private Color _selectedColor = Color.Red;
private int _regionCounter = 0;
// 叠加层图像 - 用于存储已完成绘制的矩形
private Image _rectangleOverlayImage = null;
private int _hoveredRegionIndex = -1; // 当前悬停的区域索引(-1表示没有悬停在任何区域上
// 当前选中的区域索引
private int _selectedRegionIndex = -1;
// 句柄调整相关变量
private enum ResizeHandle { None, TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left }
private ResizeHandle _currentHandle = ResizeHandle.None;
private bool _isResizing = false;
private Point _resizeStartPoint;
private Rectangle _originalRectangle;
// 区域移动相关变量
private bool _isMoving = false;
private Point _startMovePoint;
// 画笔大小相关变量
private int _currentBrushSize = 1; // 默认画笔大小为1像素
public Setting()
{
InitializeComponent();
// 设置按钮图标
SetButtonIcon();
// 初始化定时器
_timer = new Timer { Interval = 1000 };
_timer.Tick += Timer_Tick;
// 初始隐藏颜色选择按钮
btnSelectColor.Visible = false;
// 初始隐藏删除按钮
try
{
btnDeleteRegion.Visible = false;
// 初始状态/就绪状态下显示温差图按钮
btnDrawTempDiff.Visible = true;
// 初始状态下隐藏添加和删除温差图例按钮
btnAddTempDiff.Visible = false;
btnDeleteTempDiff.Visible = false;
}
catch (Exception ex)
{
Console.WriteLine("删除按钮初始化失败: " + ex.Message);
}
// 初始化温差图例DataGridView
InitializeTempDiffDataGridView();
// 初始状态下隐藏温差图例表格
dataGridViewTempDiff.Visible = false;
// 在初始化完成后调用UpdateButtonsVisibility设置初始状态确保所有按钮按照状态要求显示/隐藏
UpdateButtonsVisibility(0);
}
/// <summary>
/// 1像素画笔大小按钮点击事件
/// </summary>
private void BtnBrushSize1_Click(object sender, EventArgs e)
{
_currentBrushSize = 1;
// 更新按钮选中状态
UpdateBrushSizeButtonSelection(1);
}
/// <summary>
/// 3像素画笔大小按钮点击事件
/// </summary>
private void BtnBrushSize3_Click(object sender, EventArgs e)
{
_currentBrushSize = 3;
// 更新按钮选中状态
UpdateBrushSizeButtonSelection(3);
}
/// <summary>
/// 5像素画笔大小按钮点击事件
/// </summary>
private void BtnBrushSize5_Click(object sender, EventArgs e)
{
_currentBrushSize = 5;
// 更新按钮选中状态
UpdateBrushSizeButtonSelection(5);
}
/// <summary>
/// 10像素画笔大小按钮点击事件
/// </summary>
private void BtnBrushSize10_Click(object sender, EventArgs e)
{
_currentBrushSize = 10;
// 更新按钮选中状态
UpdateBrushSizeButtonSelection(10);
}
/// <summary>
/// 15像素画笔大小按钮点击事件
/// </summary>
private void BtnBrushSize15_Click(object sender, EventArgs e)
{
_currentBrushSize = 15;
// 更新按钮选中状态
UpdateBrushSizeButtonSelection(15);
}
/// <summary>
/// 创建表示画笔大小的图标
/// </summary>
/// <param name="size">画笔大小(像素)</param>
/// <param name="color">画笔颜色</param>
/// <returns>表示画笔大小的图标</returns>
private System.Drawing.Bitmap CreateBrushSizeImage(int size, System.Drawing.Color color)
{
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(20, 20);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
{
// 填充背景为透明色
g.Clear(System.Drawing.Color.Magenta);
// 计算正方形位置,使其居中
int x = (20 - size) / 2;
int y = (20 - size) / 2;
// 绘制正方形表示画笔大小
g.FillRectangle(new System.Drawing.SolidBrush(color), x, y, size, size);
// 添加边框
g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Black), x, y, size - 1, size - 1);
}
return bmp;
}
/// <summary>
/// 更新画笔大小按钮的选中状态
/// </summary>
/// <param name="selectedSize">当前选中的画笔大小</param>
private void UpdateBrushSizeButtonSelection(int selectedSize)
{
try
{
// 清除所有按钮的选中状态
btnBrushSize1.Checked = false;
btnBrushSize3.Checked = false;
btnBrushSize5.Checked = false;
btnBrushSize10.Checked = false;
btnBrushSize15.Checked = false;
// 设置当前选中按钮的选中状态
switch (selectedSize)
{
case 1:
btnBrushSize1.Checked = true;
break;
case 3:
btnBrushSize3.Checked = true;
break;
case 5:
btnBrushSize5.Checked = true;
break;
case 10:
btnBrushSize10.Checked = true;
break;
case 15:
btnBrushSize15.Checked = true;
break;
}
}
catch (Exception ex)
{
Console.WriteLine("更新画笔大小按钮状态失败: " + ex.Message);
}
}
/// <summary>
/// 鼠标按下事件 - 处理右击退出绘制状态、左击开始绘制矩形和开始调整区域大小
/// </summary>
// 存储温差值和对应颜色的数据结构
private List<Dictionary<string, object>> tempDiffData = new List<Dictionary<string, object>>();
private void InitializeTempDiffDataGridView()
{
// 设置整个DataGridView为可编辑以便特定列可以进入编辑状态
dataGridViewTempDiff.ReadOnly = false;
// 禁止用户添加新行
dataGridViewTempDiff.AllowUserToAddRows = false;
// 禁止用户调整行高
dataGridViewTempDiff.AllowUserToResizeRows = false;
// 添加列:温差值
DataGridViewTextBoxColumn columnTempDiff = new DataGridViewTextBoxColumn
{
Name = "tempDiffValue",
HeaderText = "温差值",
Width = 80,
ReadOnly = false, // 设置为可编辑
DefaultCellStyle = new DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleCenter }
};
// 添加列:颜色
DataGridViewTextBoxColumn columnColor = new DataGridViewTextBoxColumn
{
Name = "colorColumn",
HeaderText = "颜色",
Width = 80,
ReadOnly = true,
CellTemplate = new DataGridViewTextBoxCell()
};
// 添加列到DataGridView
dataGridViewTempDiff.Columns.Clear();
dataGridViewTempDiff.Columns.Add(columnTempDiff);
dataGridViewTempDiff.Columns.Add(columnColor);
// 设置编辑模式为编程控制,这样只有通过代码(如双击事件)才能进入编辑状态
dataGridViewTempDiff.EditMode = DataGridViewEditMode.EditProgrammatically;
// 添加单元格绘制事件用于显示颜色块
dataGridViewTempDiff.CellPainting += new DataGridViewCellPaintingEventHandler(DataGridViewTempDiff_CellPainting);
// 添加点击事件用于选择颜色和处理温差值列
dataGridViewTempDiff.CellClick += new DataGridViewCellEventHandler(DataGridViewTempDiff_CellClick);
// 添加单元格验证事件用于验证温差值输入
dataGridViewTempDiff.CellValidating += new DataGridViewCellValidatingEventHandler(DataGridViewTempDiff_CellValidating);
// 添加单元格格式化事件用于显示摄氏度符号
dataGridViewTempDiff.CellFormatting += new DataGridViewCellFormattingEventHandler(DataGridViewTempDiff_CellFormatting);
// 添加编辑控件显示事件用于设置编辑控件属性
dataGridViewTempDiff.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(DataGridViewTempDiff_EditingControlShowing);
// 添加单元格双击事件用于触发编辑模式
dataGridViewTempDiff.CellDoubleClick += new DataGridViewCellEventHandler(DataGridViewTempDiff_CellDoubleClick);
// 添加选择变更事件用于控制画笔大小按钮的显示
dataGridViewTempDiff.SelectionChanged += new EventHandler(DataGridViewTempDiff_SelectionChanged);
// 添加一些示例数据
AddSampleTempDiffData();
}
private void AddSampleTempDiffData()
{
// 清除现有数据
tempDiffData.Clear();
dataGridViewTempDiff.Rows.Clear();
// 添加示例数据并设置默认颜色
AddTempDiffRow("10°C", Color.Blue);
AddTempDiffRow("20°C", Color.Green);
AddTempDiffRow("30°C", Color.Red);
}
private void AddTempDiffRow(string tempDiffValue, Color color)
{
// 添加到数据列表
Dictionary<string, object> rowData = new Dictionary<string, object>
{
{ "tempDiffValue", tempDiffValue },
{ "color", color }
};
tempDiffData.Add(rowData);
// 添加到DataGridView
dataGridViewTempDiff.Rows.Add(tempDiffValue, "");
}
private void DataGridViewTempDiff_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
// 检查是否是温差值列
if (dataGridViewTempDiff.CurrentCell.ColumnIndex == dataGridViewTempDiff.Columns["tempDiffValue"].Index)
{
// 获取TextBox编辑控件 - 使用模式匹配
if (e.Control is TextBox tb)
{
// 清除之前的处理程序
tb.KeyPress -= new KeyPressEventHandler(TempDiffValueTextBox_KeyPress);
// 添加新的KeyPress处理程序
tb.KeyPress += new KeyPressEventHandler(TempDiffValueTextBox_KeyPress);
// 去掉°C符号只保留数值部分
string currentValue = dataGridViewTempDiff.CurrentCell.Value.ToString();
if (currentValue.Contains("°C"))
{
tb.Text = currentValue.Replace("°C", "");
tb.SelectionStart = tb.Text.Length;
}
}
}
}
private void TempDiffValueTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
// 允许输入数字、小数点和退格键
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.')
{
e.Handled = true;
}
// 只允许一个小数点
TextBox tb = sender as TextBox;
if (e.KeyChar == '.' && tb != null && tb.Text.Contains("."))
{
e.Handled = true;
}
// 检查小数点后最多一位
if (tb != null && tb.Text.Contains(".") &&
tb.Text.Substring(tb.Text.IndexOf(".")).Length > 1 &&
!char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}
private void DataGridViewTempDiff_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
// 只验证温差值列
if (e.ColumnIndex == dataGridViewTempDiff.Columns["tempDiffValue"].Index && e.RowIndex >= 0)
{
string value = e.FormattedValue.ToString().Trim();
// 去掉单位,只保留数字部分
string numericValue = System.Text.RegularExpressions.Regex.Replace(value, @"[^0-9.-]", "");
// 尝试解析输入为浮点数
if (!float.TryParse(numericValue, out float tempValue))
{
dataGridViewTempDiff.Rows[e.RowIndex].ErrorText = "请输入有效的温度值";
e.Cancel = true;
return;
}
// 验证温度范围0-100度
if (tempValue < 0 || tempValue > 100)
{
dataGridViewTempDiff.Rows[e.RowIndex].ErrorText = "温度值必须在0到100度之间";
e.Cancel = true;
return;
}
// 清除错误信息
dataGridViewTempDiff.Rows[e.RowIndex].ErrorText = string.Empty;
// 更新数据模型
if (e.RowIndex < tempDiffData.Count)
{
tempDiffData[e.RowIndex]["tempDiffValue"] = $"{tempValue}°C";
}
}
}
private void DataGridViewTempDiff_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
// 只处理温差值列
if (e.ColumnIndex == dataGridViewTempDiff.Columns["tempDiffValue"].Index && e.RowIndex >= 0)
{
// 确保值不为空
if (e.Value != null && !string.IsNullOrEmpty(e.Value.ToString()))
{
string value = e.Value.ToString();
// 确保值包含°C符号
if (!value.Contains("°C"))
{
e.Value = $"{value}°C";
e.FormattingApplied = true;
}
}
}
}
private void DataGridViewTempDiff_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
// 只处理颜色列
if (e.ColumnIndex == dataGridViewTempDiff.Columns["colorColumn"].Index && e.RowIndex >= 0)
{
// 清空单元格内容
e.PaintBackground(e.CellBounds, true);
// 确保行索引有效
if (e.RowIndex < tempDiffData.Count)
{
// 获取当前行的颜色
Color color = (Color)tempDiffData[e.RowIndex]["color"];
// 创建颜色块的绘制区域(居中显示,留出边距)
Rectangle colorBlock = new Rectangle(
e.CellBounds.X + 10,
e.CellBounds.Y + 3,
e.CellBounds.Width - 20,
e.CellBounds.Height - 6
);
// 绘制颜色块
using (SolidBrush brush = new SolidBrush(color))
{
e.Graphics.FillRectangle(brush, colorBlock);
}
// 添加边框
using (Pen pen = new Pen(Color.Black))
{
e.Graphics.DrawRectangle(pen, colorBlock);
}
}
// 标记单元格已绘制
e.Handled = true;
}
}
private void DataGridViewTempDiff_CellClick(object sender, DataGridViewCellEventArgs e)
{
// 移除颜色列点击处理逻辑,颜色列修改改为双击触发
// 温差值列点击不再直接进入编辑模式,改为双击进入
}
/// <summary>
/// 温差图例选择变更事件处理
/// </summary>
private void DataGridViewTempDiff_SelectionChanged(object sender, EventArgs e)
{
try
{
// 获取工具栏分隔条引用
ToolStripSeparator toolStripSeparator = null;
// 查找温差图例按钮和画笔大小按钮之间的分隔条
for (int i = 0; i < toolStrip.Items.Count - 1; i++)
{
if (toolStrip.Items[i] == btnDeleteTempDiff && toolStrip.Items[i + 1] is ToolStripSeparator)
{
toolStripSeparator = toolStrip.Items[i + 1] as ToolStripSeparator;
break;
}
}
// 检查当前是否在温差图绘制状态下
// 同时检查选中行和选中单元格,确保点击单元格时也能显示画笔按钮
if (_isTempDiffDrawingMode && (dataGridViewTempDiff.SelectedRows.Count > 0 || dataGridViewTempDiff.SelectedCells.Count > 0) && dataGridViewTempDiff.Visible)
{
// 显示所有画笔大小按钮
btnBrushSize1.Visible = true;
btnBrushSize3.Visible = true;
btnBrushSize5.Visible = true;
btnBrushSize10.Visible = true;
btnBrushSize15.Visible = true;
// 获取选中行的索引
int selectedRowIndex = -1;
if (dataGridViewTempDiff.SelectedRows.Count > 0)
{
selectedRowIndex = dataGridViewTempDiff.SelectedRows[0].Index;
}
else if (dataGridViewTempDiff.SelectedCells.Count > 0)
{
selectedRowIndex = dataGridViewTempDiff.SelectedCells[0].RowIndex;
}
// 如果选中行索引有效,更新画笔按钮颜色
if (selectedRowIndex >= 0 && selectedRowIndex < tempDiffData.Count)
{
Color selectedColor = (Color)tempDiffData[selectedRowIndex]["color"];
// 更新所有画笔按钮的颜色
btnBrushSize1.Image = CreateBrushSizeImage(1, selectedColor);
btnBrushSize3.Image = CreateBrushSizeImage(3, selectedColor);
btnBrushSize5.Image = CreateBrushSizeImage(5, selectedColor);
btnBrushSize10.Image = CreateBrushSizeImage(10, selectedColor);
btnBrushSize15.Image = CreateBrushSizeImage(15, selectedColor);
}
// 确保当前选中的画笔大小按钮处于选中状态
UpdateBrushSizeButtonSelection(_currentBrushSize);
// 控制分隔条可见性:当前后都有按钮显示时显示分隔条
// 前有btnDeleteTempDiff显示后有btnBrushSize1显示
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = btnDeleteTempDiff.Visible && btnBrushSize1.Visible;
}
}
else
{
// 其他所有情况都隐藏画笔大小按钮,确保在就绪状态下正确隐藏
btnBrushSize1.Visible = false;
btnBrushSize3.Visible = false;
btnBrushSize5.Visible = false;
btnBrushSize10.Visible = false;
btnBrushSize15.Visible = false;
// 隐藏分隔条
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = false;
}
}
}
catch (Exception ex)
{
Console.WriteLine("更新画笔大小按钮可见性失败: " + ex.Message);
}
}
private void DataGridViewTempDiff_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0 && e.RowIndex < tempDiffData.Count)
{
// 处理温差值列双击 - 双击时启动编辑模式
if (e.ColumnIndex == dataGridViewTempDiff.Columns["tempDiffValue"].Index)
{
dataGridViewTempDiff.BeginEdit(true);
}
// 处理颜色列双击 - 双击时打开颜色选择对话框
else if (e.ColumnIndex == dataGridViewTempDiff.Columns["colorColumn"].Index)
{
using (ColorDialog colorDialog = new ColorDialog())
{
// 设置初始颜色为当前行的颜色
colorDialog.Color = (Color)tempDiffData[e.RowIndex]["color"];
if (colorDialog.ShowDialog() == DialogResult.OK)
{
// 更新颜色数据
tempDiffData[e.RowIndex]["color"] = colorDialog.Color;
// 刷新单元格以显示新颜色
dataGridViewTempDiff.Refresh();
}
}
}
}
}
private void PicBoxTemp_MouseDown(object sender, MouseEventArgs e)
{
// 检查是否处于温差图绘制状态且右击鼠标
if (_isTempDiffDrawingMode && e.Button == MouseButtons.Right)
{
// 退出温差图绘制状态,返回到就绪状态
ExitTempDiffDrawingMode();
}
// 检查是否处于绘制状态且右击鼠标
else if (_isDrawingMode && e.Button == MouseButtons.Right)
{
// 退出绘制状态
_isDrawingMode = false;
btnDrawRegion.Checked = false;
// 重置鼠标光标
picBoxTemp.Cursor = Cursors.Default;
// 清除临时绘制
_currentRectangle = Rectangle.Empty;
_isDrawing = false;
// 按就绪状态设置按钮可见性
UpdateButtonsVisibility(0); // 0表示初始状态/就绪状态
// 更新按钮提示文本
btnDrawRegion.ToolTipText = "绘制区域(点击开启)";
// 刷新绘制
picBoxTemp.Invalidate();
}
// 处理选中区域的调整大小或移动
else if (e.Button == MouseButtons.Left && !_isDrawingMode && _selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
Rectangle controlRectangle = ImageRectangleToControlRectangle(selectedRegion.ImageRectangle);
// 检查是否点击在句柄上
_currentHandle = GetHoveredHandle(controlRectangle, e.Location);
if (_currentHandle != ResizeHandle.None)
{
// 开始调整大小
_isResizing = true;
_resizeStartPoint = e.Location;
_originalRectangle = controlRectangle;
}
else if (controlRectangle.Contains(e.Location))
{
// 开始移动区域
_isMoving = true;
_startMovePoint = e.Location;
picBoxTemp.Cursor = Cursors.SizeAll;
}
}
}
// 处理左击开始绘制矩形
else if (e.Button == MouseButtons.Left && _isDrawingMode)
{
_startPoint = e.Location;
_isDrawing = true;
_currentRectangle = new Rectangle(e.X, e.Y, 0, 0);
}
}
/// <summary>
/// 根据状态设置按钮可见性
/// </summary>
/// <param name="state">状态类型0-初始/就绪状态1-选中区域状态2-绘制状态3-温差图绘制状态</param>
private void UpdateButtonsVisibility(int state)
{
try
{
// 获取工具栏分隔条引用
ToolStripSeparator toolStripSeparator = null;
// 查找温差图例按钮和画笔大小按钮之间的分隔条
for (int i = 0; i < toolStrip.Items.Count - 1; i++)
{
if (toolStrip.Items[i] == btnDeleteTempDiff && toolStrip.Items[i + 1] is ToolStripSeparator)
{
toolStripSeparator = toolStrip.Items[i + 1] as ToolStripSeparator;
break;
}
}
switch (state)
{
case 0: // 初始状态/就绪状态
btnDrawRegion.Visible = true; // 显示绘制区域按钮
btnDrawTempDiff.Visible = true; // 显示温差图按钮
btnSelectColor.Visible = false; // 隐藏颜色选择按钮
btnDeleteRegion.Visible = false; // 隐藏删除区域按钮
dataGridViewTempDiff.Visible = false; // 隐藏温差图例表格
btnAddTempDiff.Visible = false; // 隐藏添加温差图例按钮
btnDeleteTempDiff.Visible = false; // 隐藏删除温差图例按钮
// 隐藏所有画笔大小按钮
btnBrushSize1.Visible = false;
btnBrushSize3.Visible = false;
btnBrushSize5.Visible = false;
btnBrushSize10.Visible = false;
btnBrushSize15.Visible = false;
// 控制分隔条可见性:前后都没有显示的按钮,隐藏分隔条
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = false;
}
break;
case 1: // 选中区域状态
btnDrawRegion.Visible = false; // 隐藏绘制区域按钮
btnDrawTempDiff.Visible = false; // 隐藏温差图按钮
btnSelectColor.Visible = true; // 显示颜色选择按钮
btnDeleteRegion.Visible = true; // 显示删除区域按钮
dataGridViewTempDiff.Visible = false; // 隐藏温差图例表格
btnAddTempDiff.Visible = false; // 隐藏添加温差图例按钮
btnDeleteTempDiff.Visible = false; // 隐藏删除温差图例按钮
// 隐藏所有画笔大小按钮
btnBrushSize1.Visible = false;
btnBrushSize3.Visible = false;
btnBrushSize5.Visible = false;
btnBrushSize10.Visible = false;
btnBrushSize15.Visible = false;
// 控制分隔条可见性:前后都没有显示的按钮,隐藏分隔条
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = false;
}
break;
case 2: // 绘制状态
btnSelectColor.Visible = true; // 显示颜色选择按钮
btnDrawRegion.Visible = true; // 显示绘制区域按钮
btnDeleteRegion.Visible = false; // 隐藏删除区域按钮
btnDrawTempDiff.Visible = false; // 隐藏温差图按钮
dataGridViewTempDiff.Visible = false; // 隐藏温差图例表格
btnAddTempDiff.Visible = false; // 隐藏添加温差图例按钮
btnDeleteTempDiff.Visible = false; // 隐藏删除温差图例按钮
// 隐藏所有画笔大小按钮
btnBrushSize1.Visible = false;
btnBrushSize3.Visible = false;
btnBrushSize5.Visible = false;
btnBrushSize10.Visible = false;
btnBrushSize15.Visible = false;
// 控制分隔条可见性:前后都没有显示的按钮,隐藏分隔条
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = false;
}
break;
case 3: // 温差图绘制状态
btnDrawTempDiff.Visible = true; // 显示温差图按钮
btnDrawRegion.Visible = false; // 隐藏绘制区域按钮
btnSelectColor.Visible = false; // 隐藏颜色选择按钮
btnDeleteRegion.Visible = false; // 隐藏删除区域按钮
dataGridViewTempDiff.Visible = true; // 显示温差图例表格
btnAddTempDiff.Visible = true; // 显示添加温差图例按钮
btnDeleteTempDiff.Visible = true; // 显示删除温差图例按钮
// 初始隐藏画笔大小按钮等待用户选择温差图例后在SelectionChanged事件中显示
btnBrushSize1.Visible = false;
btnBrushSize3.Visible = false;
btnBrushSize5.Visible = false;
btnBrushSize10.Visible = false;
btnBrushSize15.Visible = false;
// 控制分隔条可见性:只有前有按钮显示且后有按钮显示时才显示分隔条
// 在温差图绘制初始状态,画笔按钮默认隐藏,所以分隔条也隐藏
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = false;
}
break;
}
}
catch (Exception ex)
{
Console.WriteLine("更新按钮可见性失败: " + ex.Message);
}
}
/// <summary>
/// 绘制温差图按钮点击事件
/// </summary>
private void BtnDrawTempDiff_Click(object sender, EventArgs e)
{
try
{
// 设置温差图绘制模式标志
_isTempDiffDrawingMode = !_isTempDiffDrawingMode;
btnDrawTempDiff.Checked = _isTempDiffDrawingMode;
if (_isTempDiffDrawingMode)
{
// 进入温差图绘制状态
// 暂时使用十字光标实际光标会在MouseMove事件中根据画笔大小设置
picBoxTemp.Cursor = Cursors.Cross;
btnDrawTempDiff.ToolTipText = "温差图绘制模式已启用,点击图片区域进行绘制(点击关闭)";
// 调用按钮可见性更新方法设置为温差图绘制状态
UpdateButtonsVisibility(3); // 3表示温差图绘制状态
// 确保温差图例有数据且默认选中第一行
if (dataGridViewTempDiff.Rows.Count > 0)
{
// 清除当前选择
dataGridViewTempDiff.ClearSelection();
// 选中第一行
dataGridViewTempDiff.Rows[0].Selected = true;
// 手动触发SelectionChanged事件处理逻辑
// 这里不直接调用事件,而是直接更新画笔按钮可见性和颜色
btnBrushSize1.Visible = true;
btnBrushSize3.Visible = true;
btnBrushSize5.Visible = true;
btnBrushSize10.Visible = true;
btnBrushSize15.Visible = true;
// 更新画笔按钮颜色为第一行温差图例的颜色
if (tempDiffData.Count > 0)
{
Color selectedColor = (Color)tempDiffData[0]["color"];
// 更新所有画笔按钮的颜色
btnBrushSize1.Image = CreateBrushSizeImage(1, selectedColor);
btnBrushSize3.Image = CreateBrushSizeImage(3, selectedColor);
btnBrushSize5.Image = CreateBrushSizeImage(5, selectedColor);
btnBrushSize10.Image = CreateBrushSizeImage(10, selectedColor);
btnBrushSize15.Image = CreateBrushSizeImage(15, selectedColor);
}
// 确保当前选中的画笔大小按钮处于选中状态
UpdateBrushSizeButtonSelection(_currentBrushSize);
// 控制分隔条可见性
ToolStripSeparator toolStripSeparator = null;
for (int i = 0; i < toolStrip.Items.Count - 1; i++)
{
if (toolStrip.Items[i] == btnDeleteTempDiff && toolStrip.Items[i + 1] is ToolStripSeparator)
{
toolStripSeparator = toolStrip.Items[i + 1] as ToolStripSeparator;
break;
}
}
if (toolStripSeparator != null)
{
toolStripSeparator.Visible = btnDeleteTempDiff.Visible && btnBrushSize1.Visible;
}
}
}
else
{
// 退出温差图绘制状态,返回到就绪状态
ExitTempDiffDrawingMode();
}
}
catch (Exception ex)
{
Console.WriteLine("温差图绘制模式切换失败: " + ex.Message);
ExitTempDiffDrawingMode();
}
}
/// <summary>
/// 退出温差图绘制模式
/// </summary>
private void ExitTempDiffDrawingMode()
{
_isTempDiffDrawingMode = false;
btnDrawTempDiff.Checked = false;
// 重置鼠标光标并释放自定义光标资源
if (picBoxTemp.Cursor != Cursors.Default)
{
Cursor oldCursor = picBoxTemp.Cursor;
picBoxTemp.Cursor = Cursors.Default;
oldCursor.Dispose(); // 释放自定义光标资源
}
// 更新按钮提示文本
btnDrawTempDiff.ToolTipText = "绘制温差图";
// 按就绪状态设置按钮可见性
UpdateButtonsVisibility(0); // 0表示初始状态/就绪状态
// 刷新绘制
picBoxTemp.Invalidate();
}
/// <summary>
/// 绘制区域按钮点击事件
/// </summary>
/// <summary>
/// 添加温差图例按钮点击事件
/// </summary>
private void BtnAddTempDiff_Click(object sender, EventArgs e)
{
try
{
// 添加新的温差图例,提供默认值和颜色
int defaultTemp = tempDiffData.Count > 0 ? tempDiffData.Count * 10 : 10;
Color defaultColor = GetNextDefaultColor(tempDiffData.Count);
AddTempDiffRow($"{defaultTemp}°C", defaultColor);
}
catch (Exception ex)
{
Console.WriteLine("添加温差图例失败: " + ex.Message);
}
}
// 获取下一个默认颜色
private Color GetNextDefaultColor(int index)
{
Color[] colors = { Color.Blue, Color.Green, Color.Red, Color.Yellow, Color.Purple, Color.Orange, Color.Pink, Color.Cyan };
return colors[index % colors.Length];
}
/// <summary>
/// 删除温差图例按钮点击事件
/// </summary>
private void BtnDeleteTempDiff_Click(object sender, EventArgs e)
{
try
{
// 检查是否有选中的行
if (dataGridViewTempDiff.SelectedRows.Count > 0)
{
// 获取选中行的索引
int selectedRowIndex = dataGridViewTempDiff.SelectedRows[0].Index;
// 从数据集合中删除该行数据
if (selectedRowIndex >= 0 && selectedRowIndex < tempDiffData.Count)
{
tempDiffData.RemoveAt(selectedRowIndex);
// 从DataGridView中删除该行
dataGridViewTempDiff.Rows.RemoveAt(selectedRowIndex);
}
}
// 额外检查:如果没有选中的行但有当前单元格(显示小三角的情况)
else if (dataGridViewTempDiff.CurrentCell != null && dataGridViewTempDiff.CurrentCell.RowIndex >= 0)
{
// 获取当前单元格所在行的索引
int currentRowIndex = dataGridViewTempDiff.CurrentCell.RowIndex;
// 从数据集合中删除该行数据
if (currentRowIndex >= 0 && currentRowIndex < tempDiffData.Count)
{
tempDiffData.RemoveAt(currentRowIndex);
// 从DataGridView中删除该行
dataGridViewTempDiff.Rows.RemoveAt(currentRowIndex);
}
}
}
catch (Exception ex)
{
Console.WriteLine("删除温差图例失败: " + ex.Message);
}
}
private void BtnDrawRegion_Click(object sender, EventArgs e)
{
_isDrawingMode = btnDrawRegion.Checked;
if (_isDrawingMode)
{
// 启用绘制模式
picBoxTemp.Cursor = Cursors.Cross;
btnDrawRegion.ToolTipText = "绘制模式已启用,点击图片区域绘制矩形框(点击关闭)";
// 调用按钮可见性更新方法设置为绘制状态
UpdateButtonsVisibility(2); // 2表示绘制状态
}
else
{
// 禁用绘制模式
picBoxTemp.Cursor = Cursors.Default;
_currentRectangle = Rectangle.Empty;
btnDrawRegion.ToolTipText = "绘制温度检测区域(点击开启/关闭)";
// 重绘以清除临时矩形
picBoxTemp.Invalidate();
// 调用按钮可见性更新方法设置为就绪状态
UpdateButtonsVisibility(0); // 0表示初始状态/就绪状态
}
}
/// <summary>
/// 将控件坐标转换为图像坐标
/// </summary>
private Point ControlPointToImagePoint(Point controlPoint)
{
if (picBoxTemp.Image == null)
return controlPoint;
// 计算图像在控件中的缩放比例
float scaleX = (float)picBoxTemp.Image.Width / picBoxTemp.ClientSize.Width;
float scaleY = (float)picBoxTemp.Image.Height / picBoxTemp.ClientSize.Height;
// 计算图像坐标
return new Point(
(int)(controlPoint.X * scaleX),
(int)(controlPoint.Y * scaleY)
);
}
/// <summary>
/// 将图像坐标转换为控件坐标
/// </summary>
private Point ImagePointToControlPoint(Point imagePoint)
{
if (picBoxTemp.Image == null)
return imagePoint;
// 计算图像在控件中的缩放比例
float scaleX = (float)picBoxTemp.ClientSize.Width / picBoxTemp.Image.Width;
float scaleY = (float)picBoxTemp.ClientSize.Height / picBoxTemp.Image.Height;
// 计算控件坐标
return new Point(
(int)(imagePoint.X * scaleX),
(int)(imagePoint.Y * scaleY)
);
}
/// <summary>
/// 将图像矩形转换为控件矩形
/// </summary>
private Rectangle ImageRectangleToControlRectangle(Rectangle imageRectangle)
{
if (picBoxTemp.Image == null)
return imageRectangle;
// 计算图像在控件中的缩放比例
float scaleX = (float)picBoxTemp.ClientSize.Width / picBoxTemp.Image.Width;
float scaleY = (float)picBoxTemp.ClientSize.Height / picBoxTemp.Image.Height;
// 计算控件矩形
return new Rectangle(
(int)(imageRectangle.X * scaleX),
(int)(imageRectangle.Y * scaleY),
(int)(imageRectangle.Width * scaleX),
(int)(imageRectangle.Height * scaleY)
);
}
/// <summary>
/// 创建与画笔大小一致的自定义光标
/// </summary>
/// <param name="size">画笔大小</param>
/// <param name="color">画笔颜色</param>
/// <returns>自定义光标</returns>
private Cursor CreateCustomBrushCursor(int size, Color color)
{
try
{
// 创建一个足够大的位图以容纳画笔大小
int cursorSize = Math.Max(size, 16); // 最小16x16
Bitmap cursorBitmap = new Bitmap(cursorSize, cursorSize);
using (Graphics g = Graphics.FromImage(cursorBitmap))
{
// 清除背景为透明色
g.Clear(Color.Magenta); // Magenta作为透明色
// 计算正方形位置,使其居中
int x = (cursorSize - size) / 2;
int y = (cursorSize - size) / 2;
// 绘制正方形表示画笔大小
using (SolidBrush brush = new SolidBrush(color))
{
g.FillRectangle(brush, x, y, size, size);
}
// 添加边框以提高可见性
using (Pen pen = new Pen(Color.Black))
{
g.DrawRectangle(pen, x, y, size - 1, size - 1);
}
}
// 设置透明色
cursorBitmap.MakeTransparent(Color.Magenta);
// 创建光标,热点位于正方形中心
return new Cursor(cursorBitmap.GetHicon());
}
catch (Exception ex)
{
Console.WriteLine("创建自定义光标失败: " + ex.Message);
// 失败时返回默认光标
return Cursors.Cross;
}
}
/// <summary>
/// 鼠标移动事件 - 更新矩形大小、移动区域、检测鼠标悬停区域或更新光标
/// </summary>
private void PicBoxTemp_MouseMove(object sender, MouseEventArgs e)
{
// 温差图绘制模式下,使用自定义画笔光标
if (_isTempDiffDrawingMode)
{
// 获取当前选中的温差图例颜色
Color selectedColor = Color.Black; // 默认颜色
int selectedRowIndex = -1;
// 尝试获取选中行的颜色
if (dataGridViewTempDiff.SelectedRows.Count > 0)
{
selectedRowIndex = dataGridViewTempDiff.SelectedRows[0].Index;
}
else if (dataGridViewTempDiff.SelectedCells.Count > 0)
{
selectedRowIndex = dataGridViewTempDiff.SelectedCells[0].RowIndex;
}
// 如果选中行索引有效,获取对应的颜色
if (selectedRowIndex >= 0 && selectedRowIndex < tempDiffData.Count)
{
selectedColor = (Color)tempDiffData[selectedRowIndex]["color"];
}
// 创建并设置自定义光标
Cursor customCursor = CreateCustomBrushCursor(_currentBrushSize, selectedColor);
// 确保不重复设置相同的光标(避免资源泄漏)
if (picBoxTemp.Cursor != customCursor)
{
// 释放旧光标资源
picBoxTemp.Cursor.Dispose();
picBoxTemp.Cursor = customCursor;
}
// 如果按下鼠标左键,执行绘制操作(这里可能需要根据实际绘制逻辑补充)
if (e.Button == MouseButtons.Left)
{
// 这里可以添加实际的绘制逻辑
// 目前仅设置光标,具体绘制代码可能在其他事件中
}
return; // 温差图绘制模式下,不执行其他鼠标移动逻辑
}
// 处理调整大小
if (_isResizing && !_isDrawingMode && _selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
// 计算新的矩形大小
Rectangle newRect = CalculateNewRectangle(_originalRectangle, _resizeStartPoint, e.Location, _currentHandle);
// 确保矩形有最小尺寸
if (newRect.Width > 10 && newRect.Height > 10)
{
// 转换为图像坐标并更新区域
Point imageTopLeft = ControlPointToImagePoint(new Point(newRect.Left, newRect.Top));
Point imageBottomRight = ControlPointToImagePoint(new Point(newRect.Right, newRect.Bottom));
selectedRegion.ImageRectangle = new Rectangle(
imageTopLeft.X,
imageTopLeft.Y,
imageBottomRight.X - imageTopLeft.X,
imageBottomRight.Y - imageTopLeft.Y
);
// 重新创建叠加层以反映变化
CreateRectangleOverlayImage();
// 触发重绘
picBoxTemp.Invalidate();
}
}
}
// 处理移动区域
else if (_isMoving && !_isDrawingMode && _selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
// 计算移动距离
int deltaX = e.Location.X - _startMovePoint.X;
int deltaY = e.Location.Y - _startMovePoint.Y;
// 转换为图像坐标的移动距离
float scaleX = (float)picBoxTemp.Image.Width / picBoxTemp.ClientSize.Width;
float scaleY = (float)picBoxTemp.Image.Height / picBoxTemp.ClientSize.Height;
int imageDeltaX = (int)(deltaX * scaleX);
int imageDeltaY = (int)(deltaY * scaleY);
// 计算新的矩形位置
Rectangle newRect = new Rectangle(
selectedRegion.ImageRectangle.X + imageDeltaX,
selectedRegion.ImageRectangle.Y + imageDeltaY,
selectedRegion.ImageRectangle.Width,
selectedRegion.ImageRectangle.Height
);
// 确保矩形不会移出图像边界
if (newRect.Left >= 0 && newRect.Top >= 0 &&
newRect.Right <= picBoxTemp.Image.Width &&
newRect.Bottom <= picBoxTemp.Image.Height)
{
selectedRegion.ImageRectangle = newRect;
// 更新起始点,为下一次移动做准备
_startMovePoint = e.Location;
// 重新创建叠加层以反映变化
CreateRectangleOverlayImage();
// 触发重绘
picBoxTemp.Invalidate();
}
}
}
// 处理绘制新矩形
else if (_isDrawing && _isDrawingMode)
{
int width = e.X - _startPoint.X;
int height = e.Y - _startPoint.Y;
_currentRectangle = new Rectangle(
width > 0 ? _startPoint.X : _startPoint.X + width,
height > 0 ? _startPoint.Y : _startPoint.Y + height,
Math.Abs(width),
Math.Abs(height));
picBoxTemp.Invalidate();
}
// 处理鼠标悬停(更新光标或检测悬停区域)
else if (!_isDrawingMode && !_isDrawing && !_isResizing) // 就绪状态
{
// 如果有选中的区域,检查是否悬停在句柄上
if (_selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
Rectangle controlRectangle = ImageRectangleToControlRectangle(selectedRegion.ImageRectangle);
ResizeHandle hoveredHandle = GetHoveredHandle(controlRectangle, e.Location);
if (hoveredHandle != ResizeHandle.None)
{
// 设置相应的光标
SetCursorByHandle(hoveredHandle);
return; // 不需要检查悬停区域
}
else
{
// 重置光标
picBoxTemp.Cursor = Cursors.Default;
}
}
}
// 如果没有悬停在句柄上,检查是否悬停在区域上
if (_currentHandle == ResizeHandle.None && !_isMoving)
{
// 将鼠标坐标转换为图像坐标
Point imagePoint = ControlPointToImagePoint(e.Location);
// 检查鼠标是否在某个区域内,选择索引号最大的区域
int newHoveredRegionIndex = -1;
int maxIndex = -1;
foreach (RegionInfo region in _drawnRectangles)
{
if (region.ImageRectangle.Contains(imagePoint) && region.Index > maxIndex)
{
maxIndex = region.Index;
newHoveredRegionIndex = region.Index;
}
}
// 如果悬停的区域发生变化,更新并触发重绘
if (newHoveredRegionIndex != _hoveredRegionIndex)
{
_hoveredRegionIndex = newHoveredRegionIndex;
picBoxTemp.Invalidate();
}
}
}
}
/// <summary>
/// 存储区域信息的类,包含矩形框(图像坐标)、颜色和序号
/// </summary>
private class RegionInfo
{
// 存储相对于图像的矩形坐标
public Rectangle ImageRectangle { get; set; }
public Color Color { get; set; }
public int Index { get; set; }
}
/// <summary>
/// 创建或更新叠加层图像(完全重绘)
/// 仅在必要时调用,如图像尺寸改变或需要完全重绘
/// 使用图像坐标绘制矩形
/// </summary>
private void CreateRectangleOverlayImage()
{
// 如果PictureBox没有图像或者尺寸为0则不创建叠加层
if (picBoxTemp.Image == null || picBoxTemp.Image.Width == 0 || picBoxTemp.Image.Height == 0)
{
return;
}
// 如果叠加层图像不存在或尺寸不匹配,创建新的
if (_rectangleOverlayImage == null ||
_rectangleOverlayImage.Width != picBoxTemp.Image.Width ||
_rectangleOverlayImage.Height != picBoxTemp.Image.Height)
{
// 释放旧的叠加层图像资源
if (_rectangleOverlayImage != null)
{
_rectangleOverlayImage.Dispose();
}
// 创建新的叠加层图像
_rectangleOverlayImage = new Bitmap(picBoxTemp.Image.Width, picBoxTemp.Image.Height);
// 清除背景为透明
using (Graphics g = Graphics.FromImage(_rectangleOverlayImage))
{
g.Clear(Color.Transparent);
}
// 由于创建了新图像,需要重新绘制所有矩形
foreach (RegionInfo region in _drawnRectangles)
{
DrawRegionToOverlay(region);
}
}
else
{
// 清除现有叠加层图像
using (Graphics g = Graphics.FromImage(_rectangleOverlayImage))
{
g.Clear(Color.Transparent);
}
// 重绘所有矩形
foreach (RegionInfo region in _drawnRectangles)
{
DrawRegionToOverlay(region);
}
}
}
/// <summary>
/// 将单个区域绘制到叠加层图像
/// 用于增量绘制,避免每次都重绘所有矩形
/// 使用图像坐标绘制矩形
/// </summary>
/// <param name="region">要绘制的区域信息</param>
private void DrawRegionToOverlay(RegionInfo region)
{
if (_rectangleOverlayImage == null)
return;
using (Graphics g = Graphics.FromImage(_rectangleOverlayImage))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
// 使用每个区域自己的颜色和当前选择的画笔大小绘制矩形
g.DrawRectangle(new Pen(region.Color, _currentBrushSize), region.ImageRectangle);
// 绘制区域序号
using (Font font = new Font("Arial", 12, FontStyle.Bold))
using (SolidBrush brush = new SolidBrush(region.Color))
{
// 在矩形左上角绘制序号
Point textPosition = new Point(region.ImageRectangle.X + 5, region.ImageRectangle.Y - 15);
// 确保文本不超出图像边界
if (textPosition.Y < 0)
textPosition.Y = 5;
g.DrawString(region.Index.ToString(), font, brush, textPosition);
}
}
}
/// <summary>
/// 鼠标释放事件 - 完成矩形绘制、调整大小或移动
/// 使用增量绘制,避免每次都重绘所有矩形
/// 确保矩形坐标相对于图像而非控件
/// </summary>
private void PicBoxTemp_MouseUp(object sender, MouseEventArgs e)
{
// 结束调整大小
if (_isResizing && e.Button == MouseButtons.Left)
{
_isResizing = false;
_currentHandle = ResizeHandle.None;
picBoxTemp.Cursor = Cursors.Default;
return;
}
// 结束移动区域
if (_isMoving && e.Button == MouseButtons.Left)
{
_isMoving = false;
picBoxTemp.Cursor = Cursors.Default;
return;
}
// 结束绘制新矩形
if (_isDrawing && _isDrawingMode && e.Button == MouseButtons.Left && picBoxTemp.Image != null)
{
_isDrawing = false;
// 获取相对于图像的矩形坐标
Point imageStartPoint = ControlPointToImagePoint(new Point(_currentRectangle.X, _currentRectangle.Y));
Point imageEndPoint = ControlPointToImagePoint(new Point(_currentRectangle.Right, _currentRectangle.Bottom));
// 确保矩形有一定大小才添加(转换为图像坐标后检查)
int imageWidth = Math.Abs(imageEndPoint.X - imageStartPoint.X);
int imageHeight = Math.Abs(imageEndPoint.Y - imageStartPoint.Y);
if (imageWidth > 5 && imageHeight > 5)
{
// 计算图像坐标的矩形(确保左上角为起始点)
int imageX = Math.Min(imageStartPoint.X, imageEndPoint.X);
int imageY = Math.Min(imageStartPoint.Y, imageEndPoint.Y);
// 增加计数器并创建新的区域信息(存储图像坐标)
_regionCounter++;
RegionInfo regionInfo = new RegionInfo
{
ImageRectangle = new Rectangle(imageX, imageY, imageWidth, imageHeight),
Color = _selectedColor,
Index = _regionCounter
};
_drawnRectangles.Add(regionInfo);
// 检查是否需要完全重建叠加层
bool needFullRebuild = false;
// 如果叠加层不存在或尺寸不匹配,需要完全重建
if (_rectangleOverlayImage == null ||
_rectangleOverlayImage.Width != picBoxTemp.Image.Width ||
_rectangleOverlayImage.Height != picBoxTemp.Image.Height)
{
needFullRebuild = true;
}
if (needFullRebuild)
{
// 完全重建叠加层
CreateRectangleOverlayImage();
}
else
{
// 仅绘制新添加的矩形(增量绘制)
DrawRegionToOverlay(regionInfo);
}
// 显示绘制完成的提示
ToolStripStatusLabel statusLabel = new ToolStripStatusLabel
{
Text = string.Format("已添加检测区域{0}: 图像坐标 - X={1}, Y={2}, 宽={3}, 高={4}",
_regionCounter,
imageX, imageY, imageWidth, imageHeight)
};
// 如果有状态栏,可以添加到状态栏显示
}
_currentRectangle = Rectangle.Empty;
picBoxTemp.Invalidate();
}
}
/// <summary>
/// 绘制事件 - 显示矩形框(实现图像合并机制)
/// 处理叠加层图像的缩放,确保与控件尺寸匹配
/// 实现鼠标悬停区域填充半透明色功能
/// 实现选中区域显示八个句柄功能
/// </summary>
private void PicBoxTemp_Paint(object sender, PaintEventArgs e)
{
// 设置高质量绘图
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// 图像合并机制:先绘制叠加层(根据控件尺寸进行缩放)
if (_rectangleOverlayImage != null && picBoxTemp.Image != null)
{
// 计算缩放后的目标矩形
Rectangle destRect = new Rectangle(0, 0, picBoxTemp.ClientSize.Width, picBoxTemp.ClientSize.Height);
// 绘制缩放后的叠加层
e.Graphics.DrawImage(_rectangleOverlayImage, destRect, 0, 0, _rectangleOverlayImage.Width, _rectangleOverlayImage.Height, GraphicsUnit.Pixel);
}
// 绘制选中区域的半透明填充和八个句柄
if (!_isDrawingMode && _selectedRegionIndex != -1)
{
// 查找当前选中的区域
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
// 将图像坐标转换为控件坐标
Rectangle controlRectangle = ImageRectangleToControlRectangle(selectedRegion.ImageRectangle);
// 创建半透明的填充颜色(使用区域的颜色,但设置透明度)
Color semiTransparentColor = Color.FromArgb(100, selectedRegion.Color);
// 填充半透明矩形
using (SolidBrush brush = new SolidBrush(semiTransparentColor))
{
e.Graphics.FillRectangle(brush, controlRectangle);
}
// 绘制八个句柄
DrawHandles(e.Graphics, controlRectangle);
}
}
// 绘制悬停区域的半透明填充(就绪状态且没有选中区域时)
else if (!_isDrawingMode && _hoveredRegionIndex != -1 && _selectedRegionIndex == -1)
{
// 查找当前悬停的区域
RegionInfo hoveredRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _hoveredRegionIndex);
if (hoveredRegion != null)
{
// 将图像坐标转换为控件坐标
Rectangle controlRectangle = ImageRectangleToControlRectangle(hoveredRegion.ImageRectangle);
// 创建半透明的填充颜色(使用区域的颜色,但设置透明度)
Color semiTransparentColor = Color.FromArgb(100, hoveredRegion.Color);
// 填充半透明矩形
using (SolidBrush brush = new SolidBrush(semiTransparentColor))
{
e.Graphics.FillRectangle(brush, controlRectangle);
}
}
}
// 再绘制临时矩形(当前正在绘制的矩形,使用控件坐标)
if (!_currentRectangle.IsEmpty && _isDrawingMode && _isDrawing)
{
using (Pen dashedPen = new Pen(Color.Blue, 2))
{
dashedPen.DashPattern = new float[] { 5, 2 };
e.Graphics.DrawRectangle(dashedPen, _currentRectangle);
}
}
}
/// <summary>
/// 设置绘制区域按钮的图标
/// </summary>
private void SetButtonIcon()
{
// 创建一个表示绘制区域的图标
Bitmap icon = new Bitmap(24, 24);
using (Graphics g = Graphics.FromImage(icon))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// 清除背景为透明
g.Clear(Color.Transparent);
// 绘制外矩形
g.DrawRectangle(new Pen(Color.Black, 2), 3, 3, 18, 18);
// 绘制虚线内矩形
using (Pen dashedPen = new Pen(Color.Black, 1.5f))
{
dashedPen.DashPattern = new float[] { 2, 1 };
g.DrawRectangle(dashedPen, 5, 5, 14, 14);
}
// 绘制四个角的控制点
SolidBrush brush = new SolidBrush(Color.Black);
g.FillEllipse(brush, 6, 6, 3, 3); // 左上角
g.FillEllipse(brush, 15, 6, 3, 3); // 右上角
g.FillEllipse(brush, 6, 15, 3, 3); // 左下角
g.FillEllipse(brush, 15, 15, 3, 3); // 右下角
}
// 设置按钮图标并设置透明色
btnDrawRegion.Image = icon;
btnDrawRegion.ImageTransparentColor = Color.Transparent;
// 设置删除按钮的图标
try
{
Bitmap deleteIcon = new Bitmap(24, 24);
using (Graphics g = Graphics.FromImage(deleteIcon))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
// 清除背景为透明
g.Clear(Color.Transparent);
// 绘制一个红色的叉号作为删除图标
Pen deletePen = new Pen(Color.Red, 3);
g.DrawLine(deletePen, 6, 6, 18, 18); // 从左上角到右下角的线
g.DrawLine(deletePen, 18, 6, 6, 18); // 从右上角到左下角的线
}
btnDeleteRegion.Image = deleteIcon;
btnDeleteRegion.ImageTransparentColor = Color.Transparent;
}
catch (Exception ex)
{
Console.WriteLine("删除按钮图标设置失败: " + ex.Message);
}
// 设置颜色选择按钮的图标
UpdateColorButtonIcon();
// 设置绘制温差图按钮的图标
try
{
Bitmap tempDiffIcon = new Bitmap(24, 24);
using (Graphics g = Graphics.FromImage(tempDiffIcon))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
// 清除背景为透明
g.Clear(Color.Transparent);
// 绘制表示温差的图标 - 使用渐变效果
// 绘制底部蓝色(低温)和顶部红色(高温)的矩形条
using (LinearGradientBrush gradientBrush = new LinearGradientBrush(
new Rectangle(8, 5, 8, 14),
Color.Blue, // 低温端
Color.Red, // 高温端
LinearGradientMode.Vertical))
{
g.FillRectangle(gradientBrush, 8, 5, 8, 14);
}
// 添加边框
g.DrawRectangle(new Pen(Color.Black, 1), 8, 5, 8, 14);
}
btnDrawTempDiff.Image = tempDiffIcon;
btnDrawTempDiff.ImageTransparentColor = Color.Transparent;
}
catch (Exception ex)
{
Console.WriteLine("温差图按钮图标设置失败: " + ex.Message);
}
// 设置添加温差图例按钮的图标
try
{
Bitmap addTempDiffIcon = new Bitmap(24, 24);
using (Graphics g = Graphics.FromImage(addTempDiffIcon))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
// 清除背景为透明
g.Clear(Color.Transparent);
// 绘制加号图标
Pen pen = new Pen(Color.Black, 2);
// 绘制水平线
g.DrawLine(pen, 8, 12, 16, 12);
// 绘制垂直线
g.DrawLine(pen, 12, 8, 12, 16);
}
btnAddTempDiff.Image = addTempDiffIcon;
btnAddTempDiff.ImageTransparentColor = Color.Transparent;
}
catch (Exception ex)
{
Console.WriteLine("添加温差图例按钮图标设置失败: " + ex.Message);
}
// 设置删除温差图例按钮的图标
try
{
Bitmap deleteTempDiffIcon = new Bitmap(24, 24);
using (Graphics g = Graphics.FromImage(deleteTempDiffIcon))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
// 清除背景为透明
g.Clear(Color.Transparent);
// 绘制减号图标
Pen pen = new Pen(Color.Black, 2);
// 绘制水平线
g.DrawLine(pen, 8, 12, 16, 12);
}
btnDeleteTempDiff.Image = deleteTempDiffIcon;
btnDeleteTempDiff.ImageTransparentColor = Color.Transparent;
}
catch (Exception ex)
{
Console.WriteLine("删除温差图例按钮图标设置失败: " + ex.Message);
}
}
/// <summary>
/// 更新颜色选择按钮的图标显示_selectedColor颜色的矩形
/// </summary>
private void UpdateColorButtonIcon()
{
// 创建颜色选择按钮的图标
Bitmap colorIcon = new Bitmap(24, 24);
using (Graphics g = Graphics.FromImage(colorIcon))
{
// 设置高质量绘图
g.SmoothingMode = SmoothingMode.AntiAlias;
// 清除背景为透明
g.Clear(Color.Transparent);
// 绘制边框
g.DrawRectangle(new Pen(Color.Black, 1), 3, 3, 18, 18);
// 使用_selectedColor填充矩形
using (SolidBrush brush = new SolidBrush(_selectedColor))
{
g.FillRectangle(brush, 4, 4, 16, 16);
}
}
// 设置按钮图标并设置透明色
btnSelectColor.Image = colorIcon;
btnSelectColor.ImageTransparentColor = Color.Transparent;
// 启用双缓冲以减少闪烁
typeof(PictureBox).InvokeMember("DoubleBuffered",
System.Reflection.BindingFlags.SetProperty |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic,
null, picBoxTemp, new object[] { true });
}
/// <summary>
/// 颜色选择按钮点击事件
/// </summary>
private void BtnSelectColor_Click(object sender, EventArgs e)
{
using (ColorDialog colorDialog = new ColorDialog())
{
// 设置初始颜色为当前选中的颜色
colorDialog.Color = _selectedColor;
// 允许自定义颜色
colorDialog.AllowFullOpen = true;
colorDialog.FullOpen = true;
// 显示颜色选择对话框
if (colorDialog.ShowDialog() == DialogResult.OK)
{
// 更新选中的颜色
_selectedColor = colorDialog.Color;
// 更新按钮图标,显示新选择的颜色
UpdateColorButtonIcon();
// 如果有区域被选中,更新该区域的颜色
if (_selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
selectedRegion.Color = _selectedColor;
// 重新创建叠加层图像以反映颜色变化
CreateRectangleOverlayImage();
}
}
// 重绘图片区域,显示新颜色的矩形
picBoxTemp.Invalidate();
}
}
}
/// <summary>
/// 窗口显示时启动定时器
/// </summary>
private void Setting_Shown(object sender, EventArgs e)
{
// 仅在非设计模式下启动定时器
if (!DesignMode)
{
_timer.Start();
// 立即执行一次定时器事件,避免首次显示时的延迟
Timer_Tick(sender, e);
}
}
/// <summary>
/// 删除按钮点击事件
/// </summary>
private void BtnDeleteRegion_Click(object sender, EventArgs e)
{
// 确保有选中的区域
if (_selectedRegionIndex != -1)
{
// 查找并移除选中的区域
RegionInfo regionToRemove = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (regionToRemove != null)
{
_drawnRectangles.Remove(regionToRemove);
// 取消选中状态
_selectedRegionIndex = -1;
// 使用统一的方法更新按钮可见性,设置为就绪状态
UpdateButtonsVisibility(0);
// 重绘叠加层
CreateRectangleOverlayImage();
// 触发重绘
picBoxTemp.Invalidate();
}
}
}
/// <summary>
/// 窗口关闭时停止定时器并释放资源
/// </summary>
private void Setting_FormClosing(object sender, FormClosingEventArgs e)
{
_timer.Stop();
// 释放叠加层图像资源
if (_rectangleOverlayImage != null)
{
_rectangleOverlayImage.Dispose();
_rectangleOverlayImage = null;
}
}
/// <summary>
/// 定时器每秒触发的事件处理方法
/// </summary>
/// <summary>
/// 获取鼠标当前悬停的句柄
/// </summary>
/// <param name="rectangle">控件坐标的矩形</param>
/// <param name="mousePoint">鼠标坐标</param>
/// <returns>鼠标悬停的句柄类型</returns>
private ResizeHandle GetHoveredHandle(Rectangle rectangle, Point mousePoint)
{
int handleSize = 8; // 句柄检测范围稍大,提高用户体验
// 检查各个句柄
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left - handleSize/2, rectangle.Top - handleSize/2, handleSize, handleSize)))
return ResizeHandle.TopLeft;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left + rectangle.Width/2 - handleSize/2, rectangle.Top - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Top;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Right - handleSize/2, rectangle.Top - handleSize/2, handleSize, handleSize)))
return ResizeHandle.TopRight;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Right - handleSize/2, rectangle.Top + rectangle.Height/2 - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Right;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Right - handleSize/2, rectangle.Bottom - handleSize/2, handleSize, handleSize)))
return ResizeHandle.BottomRight;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left + rectangle.Width/2 - handleSize/2, rectangle.Bottom - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Bottom;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left - handleSize/2, rectangle.Bottom - handleSize/2, handleSize, handleSize)))
return ResizeHandle.BottomLeft;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left - handleSize/2, rectangle.Top + rectangle.Height/2 - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Left;
return ResizeHandle.None;
}
/// <summary>
/// 检查点是否在矩形区域内
/// </summary>
private bool IsPointInRegion(Point point, Rectangle region)
{
return region.Contains(point);
}
/// <summary>
/// 根据句柄类型设置光标
/// </summary>
private void SetCursorByHandle(ResizeHandle handle)
{
switch (handle)
{
case ResizeHandle.TopLeft:
case ResizeHandle.BottomRight:
picBoxTemp.Cursor = Cursors.SizeNWSE;
break;
case ResizeHandle.TopRight:
case ResizeHandle.BottomLeft:
picBoxTemp.Cursor = Cursors.SizeNESW;
break;
case ResizeHandle.Top:
case ResizeHandle.Bottom:
picBoxTemp.Cursor = Cursors.SizeNS;
break;
case ResizeHandle.Left:
case ResizeHandle.Right:
picBoxTemp.Cursor = Cursors.SizeWE;
break;
default:
picBoxTemp.Cursor = Cursors.Default;
break;
}
}
/// <summary>
/// 根据鼠标移动计算新的矩形大小
/// </summary>
private Rectangle CalculateNewRectangle(Rectangle original, Point startPoint, Point currentPoint, ResizeHandle handle)
{
Rectangle newRect = original;
switch (handle)
{
case ResizeHandle.TopLeft:
newRect.X = currentPoint.X;
newRect.Y = currentPoint.Y;
newRect.Width = original.Right - currentPoint.X;
newRect.Height = original.Bottom - currentPoint.Y;
break;
case ResizeHandle.Top:
newRect.Y = currentPoint.Y;
newRect.Height = original.Bottom - currentPoint.Y;
break;
case ResizeHandle.TopRight:
newRect.Y = currentPoint.Y;
newRect.Width = currentPoint.X - original.Left;
newRect.Height = original.Bottom - currentPoint.Y;
break;
case ResizeHandle.Right:
newRect.Width = currentPoint.X - original.Left;
break;
case ResizeHandle.BottomRight:
newRect.Width = currentPoint.X - original.Left;
newRect.Height = currentPoint.Y - original.Top;
break;
case ResizeHandle.Bottom:
newRect.Height = currentPoint.Y - original.Top;
break;
case ResizeHandle.BottomLeft:
newRect.X = currentPoint.X;
newRect.Width = original.Right - currentPoint.X;
newRect.Height = currentPoint.Y - original.Top;
break;
case ResizeHandle.Left:
newRect.X = currentPoint.X;
newRect.Width = original.Right - currentPoint.X;
break;
}
// 确保矩形不会变成负尺寸
if (newRect.Width < 0)
{
newRect.X += newRect.Width;
newRect.Width = Math.Abs(newRect.Width);
}
if (newRect.Height < 0)
{
newRect.Y += newRect.Height;
newRect.Height = Math.Abs(newRect.Height);
}
return newRect;
}
/// <summary>
/// 绘制矩形的八个句柄
/// </summary>
/// <param name="g">绘图对象</param>
/// <param name="rectangle">要绘制句柄的矩形(控件坐标)</param>
private void DrawHandles(Graphics g, Rectangle rectangle)
{
// 句柄大小
int handleSize = 6;
// 句柄颜色
Color handleColor = Color.White;
Color handleBorderColor = Color.Black;
// 八个句柄的位置
Point[] handlePoints = new Point[]
{
// 左上角
new Point(rectangle.Left, rectangle.Top),
// 上中
new Point(rectangle.Left + rectangle.Width / 2, rectangle.Top),
// 右上角
new Point(rectangle.Right, rectangle.Top),
// 右中
new Point(rectangle.Right, rectangle.Top + rectangle.Height / 2),
// 右下角
new Point(rectangle.Right, rectangle.Bottom),
// 下中
new Point(rectangle.Left + rectangle.Width / 2, rectangle.Bottom),
// 左下角
new Point(rectangle.Left, rectangle.Bottom),
// 左中
new Point(rectangle.Left, rectangle.Top + rectangle.Height / 2)
};
// 绘制每个句柄
using (SolidBrush handleBrush = new SolidBrush(handleColor))
using (Pen handleBorderPen = new Pen(handleBorderColor, 1))
{
foreach (Point point in handlePoints)
{
// 计算句柄矩形
Rectangle handleRect = new Rectangle(
point.X - handleSize / 2,
point.Y - handleSize / 2,
handleSize,
handleSize);
// 绘制句柄(白色填充,黑色边框)
g.FillRectangle(handleBrush, handleRect);
g.DrawRectangle(handleBorderPen, handleRect);
}
}
}
/// <summary>
/// 鼠标点击事件 - 处理区域选中和右击退出选中状态
/// </summary>
private void PicBoxTemp_MouseClick(object sender, MouseEventArgs e)
{
// 如果处于温差图绘制状态不执行任何操作只有右击在MouseDown事件中处理退出
if (_isTempDiffDrawingMode)
{
return;
}
// 处理右键点击 - 退出选中状态
if (!_isDrawingMode && e.Button == MouseButtons.Right && _selectedRegionIndex != -1)
{
// 取消选中状态
_selectedRegionIndex = -1;
// 使用统一的方法更新按钮可见性,设置为就绪状态
UpdateButtonsVisibility(0); // 0表示初始状态/就绪状态
// 刷新绘制
picBoxTemp.Invalidate();
return; // 处理完右键事件后返回
}
// 仅在就绪状态(非绘制模式)下处理左键点击
if (!_isDrawingMode && e.Button == MouseButtons.Left && picBoxTemp.Image != null && !_isResizing)
{
// 将控件坐标转换为图像坐标
Point imagePoint = ControlPointToImagePoint(e.Location);
// 检查是否点击在某个区域内
bool clickedOnRegion = false;
foreach (RegionInfo region in _drawnRectangles)
{
if (region.ImageRectangle.Contains(imagePoint))
{
// 选中该区域(点击已选中区域不再取消选中)
_selectedRegionIndex = region.Index;
clickedOnRegion = true;
break;
}
}
// 如果没有点击在任何区域上,取消选中
if (!clickedOnRegion)
{
_selectedRegionIndex = -1;
}
// 更新按钮的可见性
try
{
bool isRegionSelected = (_selectedRegionIndex != -1);
if (isRegionSelected)
{
// 选中区域状态
UpdateButtonsVisibility(1);
}
else
{
// 就绪状态
UpdateButtonsVisibility(0);
}
}
catch (Exception ex)
{
Console.WriteLine("更新按钮可见性失败: " + ex.Message);
}
// 刷新绘制
picBoxTemp.Invalidate();
}
}
/// <summary>
/// 当图像更新或控件大小变化时,重新创建叠加层图像
/// 确保矩形框正确显示在新的尺寸下
/// </summary>
private void UpdateOverlayForSizeChange()
{
if (picBoxTemp.Image != null && _drawnRectangles.Count > 0)
{
CreateRectangleOverlayImage();
picBoxTemp.Invalidate();
}
}
/// <summary>
/// 当控件大小改变时,更新叠加层以确保矩形框正确缩放
/// </summary>
private void PicBoxTemp_SizeChanged(object sender, EventArgs e)
{
UpdateOverlayForSizeChange();
}
private void Timer_Tick(object sender, EventArgs e)
{
// 这里可以添加每秒需要执行的代码
// 例如:更新界面数据、检查状态等
if (DesignMode || this.IsDisposed || this.Disposing)
return;
// 线程安全检查 - 确保在UI线程上执行
if (this.InvokeRequired)
{
try
{
this.BeginInvoke(new Action(UpdatePictureBoxImage));
}
catch (ObjectDisposedException)
{
// 控件已释放,忽略
}
return;
}
UpdatePictureBoxImage();
}
/// <summary>
/// 更新PictureBox图像的辅助方法
/// 此方法必须在UI线程上执行
/// </summary>
private void UpdatePictureBoxImage()
{
}
/// <summary>
/// 更新pictureBoxTemperatureDisplay的图像
/// 此方法可以从任何线程调用
/// 注意:根据要求,不修改此方法的核心逻辑
/// </summary>
/// <param name="NewImage">要显示的新图像</param>
public void UpdateRealTimeImage(Image NewImage)
{
// 空值检查
if (NewImage == null)
{
Console.WriteLine("传入UpdateRealTimeImage的图像为空");
return;
}
// 检查是否处于设计模式或窗口不可见
if (DesignMode || !this.Visible || this.IsDisposed || this.Disposing)
{
// 如果不满足条件,释放图像资源并返回
NewImage.Dispose();
return;
}
try
{
// 线程安全检查 - 确保在UI线程上执行
if (this.InvokeRequired)
{
try
{
// 使用BeginInvoke在UI线程上更新图像
this.BeginInvoke(new Action(() =>
{
try
{
// 确保窗口未被释放
if (!this.IsDisposed && !this.Disposing && picBoxTemp != null && !picBoxTemp.IsDisposed)
{
// 保存旧图像引用,以便在设置新图像后释放
Image oldImage = picBoxTemp.Image;
// 设置新图像
picBoxTemp.Image = NewImage;
// 释放旧图像资源
if (oldImage != null && oldImage != NewImage)
{
oldImage.Dispose();
}
}
else
{
// 如果控件已释放,确保释放图像资源
NewImage.Dispose();
}
}
catch (Exception ex)
{
Console.WriteLine($"更新设置窗口图像失败: {ex.Message}");
// 确保在异常情况下释放图像资源
try
{
NewImage.Dispose();
}
catch {}
}
}));
}
catch (ObjectDisposedException)
{
// 控件已释放,忽略并释放图像资源
NewImage.Dispose();
}
return;
}
// 在UI线程上直接更新图像
if (!this.IsDisposed && !this.Disposing && picBoxTemp != null && !picBoxTemp.IsDisposed)
{
// 保存旧图像引用,以便在设置新图像后释放
Image oldImage = picBoxTemp.Image;
// 设置新图像
picBoxTemp.Image = NewImage;
// 释放旧图像资源
if (oldImage != null && oldImage != NewImage)
{
oldImage.Dispose();
}
}
else
{
// 如果控件已释放,确保释放图像资源
NewImage.Dispose();
}
}
catch (Exception ex)
{
Console.WriteLine($"处理实时图像更新时出错: {ex.Message}");
// 确保在任何异常情况下都释放图像资源
try
{
NewImage.Dispose();
}
catch {}
}
}
}
}