diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Properties/AssemblyInfo.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Properties/AssemblyInfo.cs
index 4a10be8..51de4bc 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/Properties/AssemblyInfo.cs
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/Properties/AssemblyInfo.cs
@@ -33,6 +33,6 @@ using System.Runtime.InteropServices;
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.2.5")]
-[assembly: AssemblyFileVersion("1.0.2.7")]
+[assembly: AssemblyFileVersion("1.0.2.8")]
// NuGet包相关信息已在项目文件中配置
diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/preview.cs b/Windows/CS/Framework4.0/Toprie/Toprie/preview.cs
index 84fc221..5cfd760 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/preview.cs
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/preview.cs
@@ -14,12 +14,27 @@ namespace JoyD.Windows.CS
///
public partial class preview : Form
{
+ // 原始温度数据矩阵尺寸
+ private const int DATA_WIDTH = 256;
+ private const int DATA_HEIGHT = 192;
+ // 热力图显示尺寸
+ private const int DISPLAY_WIDTH = 512;
+ private const int DISPLAY_HEIGHT = 384;
+
+ // 鼠标当前指向的数据点坐标
+ private Point _currentDataPoint = new Point(-1, -1);
+ // 用于保护_currentDataPoint访问的锁对象
+ private readonly object _dataPointLock = new object();
+
///
/// 初始化预览窗口的构造函数
///
public preview()
{
InitializeComponent();
+ previewImageBox.MouseMove += PreviewImageBox_MouseMove;
+ previewImageBox.MouseLeave += PreviewImageBox_MouseLeave;
+ previewImageBox.Paint += PreviewImageBox_Paint;
}
///
@@ -48,6 +63,9 @@ namespace JoyD.Windows.CS
{
previewImageBox.Image = (Image)image.Clone();
}
+
+ // 图像更新后,确保重绘以保持覆盖层正确
+ previewImageBox.Invalidate();
}
catch (Exception ex)
{
@@ -62,6 +80,11 @@ namespace JoyD.Windows.CS
{
base.OnFormClosed(e);
+ // 移除事件绑定
+ previewImageBox.MouseMove -= PreviewImageBox_MouseMove;
+ previewImageBox.MouseLeave -= PreviewImageBox_MouseLeave;
+ previewImageBox.Paint -= PreviewImageBox_Paint;
+
// 释放图像资源
if (previewImageBox.Image != null)
{
@@ -69,5 +92,126 @@ namespace JoyD.Windows.CS
previewImageBox.Image = null;
}
}
+
+ // 鼠标移动事件处理
+ private void PreviewImageBox_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (previewImageBox.Image == null) return;
+
+ // 计算鼠标在图像上的坐标(考虑图像缩放)
+ Point imagePoint = GetImagePoint(e.Location);
+
+ // 映射到原始数据点坐标
+ Point dataPoint = MapToDataPoint(imagePoint);
+
+ // 使用锁保护_currentDataPoint的访问
+ lock (_dataPointLock)
+ {
+ // 如果数据点发生变化,重绘控件
+ if (_currentDataPoint != dataPoint)
+ {
+ _currentDataPoint = dataPoint;
+ previewImageBox.Invalidate(); // 触发Paint事件重绘
+ }
+ }
+ }
+
+ // 鼠标离开事件处理
+ private void PreviewImageBox_MouseLeave(object sender, EventArgs e)
+ {
+ // 使用锁保护_currentDataPoint的访问
+ lock (_dataPointLock)
+ {
+ _currentDataPoint = new Point(-1, -1);
+ previewImageBox.Invalidate(); // 触发Paint事件重绘
+ }
+ }
+
+ // 将控件坐标转换为图像坐标
+ private Point GetImagePoint(Point controlPoint)
+ {
+ if (previewImageBox.Image == null)
+ return controlPoint;
+
+ // 计算图像在控件中的缩放比例
+ // SizeMode = StretchImage 将图像拉伸填满整个PictureBox
+ // 控件左上角对应图像左上角,控件右下角对应图像右下角
+ float scaleX = (float)previewImageBox.Image.Width / previewImageBox.ClientSize.Width;
+ float scaleY = (float)previewImageBox.Image.Height / previewImageBox.ClientSize.Height;
+
+ // 计算图像坐标
+ return new Point(
+ (int)(controlPoint.X * scaleX),
+ (int)(controlPoint.Y * scaleY)
+ );
+ }
+
+ // 将图像坐标映射到原始数据点坐标
+ private Point MapToDataPoint(Point imagePoint)
+ {
+ // 确保坐标在有效范围内
+ int x = Math.Max(0, Math.Min(imagePoint.X, DISPLAY_WIDTH - 1));
+ int y = Math.Max(0, Math.Min(imagePoint.Y, DISPLAY_HEIGHT - 1));
+
+ // 计算原始数据点坐标(整数除法,向下取整)
+ return new Point(x / 2, y / 2);
+ }
+
+ // 将原始数据点坐标映射到热力图覆盖区域
+ private Rectangle GetDataPointCoverageArea(Point dataPoint)
+ {
+ // 确保数据点在有效范围内
+ int x = Math.Max(0, Math.Min(dataPoint.X, DATA_WIDTH - 1));
+ int y = Math.Max(0, Math.Min(dataPoint.Y, DATA_HEIGHT - 1));
+
+ // 计算覆盖区域(2×2像素)
+ return new Rectangle(x * 2, y * 2, 2, 2);
+ }
+
+ // Paint事件处理函数
+ private void PreviewImageBox_Paint(object sender, PaintEventArgs e)
+ {
+ // 边界检查:如果没有图像,不需要绘制覆盖层
+ if (previewImageBox.Image == null)
+ return;
+
+ // 使用锁保护_currentDataPoint的访问并进行有效性检查
+ Point currentDataPoint;
+ lock (_dataPointLock)
+ {
+ currentDataPoint = _currentDataPoint;
+ // 如果没有有效的数据点,不需要绘制覆盖层
+ if (currentDataPoint.X < 0 || currentDataPoint.Y < 0)
+ return;
+ }
+
+ // 计算数据点在图像坐标系中的覆盖区域
+ Rectangle imageArea = GetDataPointCoverageArea(currentDataPoint);
+
+ // 转换为控件坐标系
+ float scaleX = (float)previewImageBox.ClientSize.Width / previewImageBox.Image.Width;
+ float scaleY = (float)previewImageBox.ClientSize.Height / previewImageBox.Image.Height;
+
+ Rectangle controlArea = new Rectangle(
+ (int)(imageArea.X * scaleX),
+ (int)(imageArea.Y * scaleY),
+ (int)(imageArea.Width * scaleX),
+ (int)(imageArea.Height * scaleY)
+ );
+
+ // 使用using语句确保GDI+资源正确释放
+ using (Brush semiTransparentRed = new SolidBrush(Color.FromArgb(128, Color.Red)))
+ {
+ // 绘制覆盖层
+ e.Graphics.FillRectangle(semiTransparentRed, controlArea);
+
+ // 使用using语句确保Pen资源正确释放
+ using (Pen borderPen = new Pen(Color.Red, 1))
+ {
+ // 可选:绘制矩形边框以增强视觉效果
+ e.Graphics.DrawRectangle(borderPen, controlArea);
+ }
+ }
+ }
}
}