修复Toprie热像仪实时温度信息显示问题,调整UpdateImageOnUI方法实现和UpdateRealTimeInfoOnUI方法语法错误
This commit is contained in:
@@ -31,6 +31,10 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
// 信息图像,用于显示额外信息
|
// 信息图像,用于显示额外信息
|
||||||
private Image _infoImage = null;
|
private Image _infoImage = null;
|
||||||
|
|
||||||
|
// 实时信息图像,用于显示温度等实时数据
|
||||||
|
private Image _displayImage = null;
|
||||||
|
private readonly object _displayImageLock = new object();
|
||||||
|
|
||||||
// 最近一次获取到的温度数据
|
// 最近一次获取到的温度数据
|
||||||
|
|
||||||
// 温度显示状态标志
|
// 温度显示状态标志
|
||||||
@@ -390,6 +394,17 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
Console.WriteLine("InfoImage已初始化为透明bitmap");
|
Console.WriteLine("InfoImage已初始化为透明bitmap");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化DisplayImage为透明bitmap
|
||||||
|
lock (_displayImageLock)
|
||||||
|
{
|
||||||
|
_displayImage = new Bitmap(BUFFER_WIDTH, BUFFER_HEIGHT);
|
||||||
|
using (Graphics g = Graphics.FromImage(_displayImage))
|
||||||
|
{
|
||||||
|
g.Clear(Color.Transparent);
|
||||||
|
}
|
||||||
|
Console.WriteLine("DisplayImage已初始化为透明bitmap");
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化图像框的bitmap为透明
|
// 初始化图像框的bitmap为透明
|
||||||
if (imageBox != null && !imageBox.IsDisposed)
|
if (imageBox != null && !imageBox.IsDisposed)
|
||||||
{
|
{
|
||||||
@@ -771,50 +786,17 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 步骤3:在就绪条件下,如果有温度数据(时间在最近3秒内),显示最高温度(居中显示)
|
// 步骤2.1:绘制DisplayImage(实时温度信息等)
|
||||||
if (!_isPaused && IsDevicePingable && _deviceManager != null && _deviceManager.ConnectionStatus == ConnectionStatus.Connected)
|
lock (_displayImageLock)
|
||||||
{
|
{
|
||||||
TemperatureData temperatureData = _deviceManager.LastTemperature;
|
if (_displayImage != null)
|
||||||
if (temperatureData != null && temperatureData.Timestamp != null)
|
|
||||||
{
|
{
|
||||||
// 检查温度数据时间是否在最近3秒内
|
g.DrawImage(_displayImage, 0, 0);
|
||||||
TimeSpan timeDiff = DateTime.Now - temperatureData.Timestamp;
|
|
||||||
if (timeDiff.TotalSeconds <= 3)
|
|
||||||
{
|
|
||||||
// 有有效温度数据,居中显示最高温度
|
|
||||||
string tempText = $"最高温度: {temperatureData.MaxTemperature:F2} °C";
|
|
||||||
Color textColor = Color.White;
|
|
||||||
|
|
||||||
using (Font font = new Font("Arial", 24, FontStyle.Bold))
|
|
||||||
using (SolidBrush textBrush = new SolidBrush(textColor))
|
|
||||||
{
|
|
||||||
StringFormat format = new StringFormat() {
|
|
||||||
Alignment = StringAlignment.Center,
|
|
||||||
LineAlignment = StringAlignment.Center
|
|
||||||
};
|
|
||||||
|
|
||||||
// 计算文本位置,确保居中显示
|
|
||||||
RectangleF textRect = new RectangleF(0, 0, BUFFER_WIDTH, BUFFER_HEIGHT);
|
|
||||||
|
|
||||||
// 添加半透明背景以提高可读性
|
|
||||||
SizeF textSize = g.MeasureString(tempText, font);
|
|
||||||
RectangleF bgRect = new RectangleF(
|
|
||||||
(BUFFER_WIDTH - textSize.Width - 20) / 2,
|
|
||||||
(BUFFER_HEIGHT - textSize.Height - 20) / 2,
|
|
||||||
textSize.Width + 20,
|
|
||||||
textSize.Height + 20
|
|
||||||
);
|
|
||||||
using (SolidBrush bgBrush = new SolidBrush(Color.FromArgb(128, 0, 0, 0)))
|
|
||||||
{
|
|
||||||
g.FillRectangle(bgBrush, bgRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 居中绘制温度信息
|
|
||||||
g.DrawString(tempText, font, textBrush, textRect, format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注意:温度信息不再直接在这里绘制
|
||||||
|
// 而是在UpdateRealTimeInfoOnUI方法中绘制到_displayImage,然后在这里绘制到_imageBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在同一个锁内创建缓冲区的副本,避免重复锁定
|
// 在同一个锁内创建缓冲区的副本,避免重复锁定
|
||||||
@@ -1771,6 +1753,24 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放DisplayImage资源
|
||||||
|
lock (_displayImageLock)
|
||||||
|
{
|
||||||
|
if (_displayImage != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_displayImage.Dispose();
|
||||||
|
_displayImage = null;
|
||||||
|
Console.WriteLine("DisplayImage资源已释放");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"清理DisplayImage资源异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 释放组件资源
|
// 释放组件资源
|
||||||
if (components != null)
|
if (components != null)
|
||||||
{
|
{
|
||||||
@@ -1853,123 +1853,129 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateRealTimeInfoOnUI()
|
private void UpdateRealTimeInfoOnUI()
|
||||||
{
|
{
|
||||||
// 1. 以透明色清空图像缓冲区的温度显示区域
|
lock (_displayImageLock)
|
||||||
// 遵循README要求:中途不进行Dispose和设置为null,只在上面进行绘制
|
|
||||||
if (_imageBuffer == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using (Graphics g = Graphics.FromImage(_imageBuffer))
|
|
||||||
{
|
{
|
||||||
// 清除DisplayImage为透明色
|
// 1. 以透明色清空DisplayImage
|
||||||
g.Clear(Color.Transparent);
|
// 遵循README要求:中途不进行Dispose和设置为null,只在上面进行绘制
|
||||||
|
if (_displayImage == null)
|
||||||
// 2. 如果没有温度数据或温度数据的时间3秒之前,返回
|
|
||||||
TemperatureData temperatureData = _deviceManager.LastTemperature;
|
|
||||||
if (temperatureData == null || temperatureData.Timestamp == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TimeSpan timeDiff = DateTime.Now - temperatureData.Timestamp;
|
using (Graphics g = Graphics.FromImage(_displayImage))
|
||||||
if (timeDiff.TotalSeconds > 3)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 3. 温度显示菜单下如果未勾选区域温度和全局温度,则不显示任何温度信息
|
|
||||||
if (!_showGlobalTemperature && !_showAreaTemperature)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 4. 如果勾选了全局温度,则显示全局温度(居中显示),否则显示区域温度(居中显示)
|
|
||||||
bool isGlobalTemperatureMode = _showGlobalTemperature;
|
|
||||||
|
|
||||||
// 5. 如果勾选了区域温度,则显示区域框,否则不显示区域框
|
|
||||||
if (_showAreaTemperature)
|
|
||||||
{
|
{
|
||||||
try
|
// 清除DisplayImage为透明色
|
||||||
|
g.Clear(Color.Transparent);
|
||||||
|
|
||||||
|
// 2. 如果没有温度数据或温度数据的时间3秒之前,返回
|
||||||
|
TemperatureData temperatureData = _deviceManager.LastTemperature;
|
||||||
|
if (temperatureData == null || temperatureData.Timestamp == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TimeSpan timeDiff = DateTime.Now - temperatureData.Timestamp;
|
||||||
|
if (timeDiff.TotalSeconds > 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 3. 温度显示菜单下如果未勾选区域温度和全局温度,则不显示任何温度信息
|
||||||
|
if (!_showGlobalTemperature && !_showAreaTemperature)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 4. 如果勾选了全局温度,则显示全局温度(居中显示),否则显示区域温度(居中显示)
|
||||||
|
bool isGlobalTemperatureMode = _showGlobalTemperature;
|
||||||
|
|
||||||
|
// 5. 如果勾选了区域温度,则显示区域框,否则不显示区域框
|
||||||
|
if (_showAreaTemperature)
|
||||||
{
|
{
|
||||||
// 由于DeviceManager没有V8属性,暂时跳过区域框的绘制
|
try
|
||||||
// 注意:在实际应用中,应该通过正确的API获取区域位置信息
|
{
|
||||||
Console.WriteLine("区域温度显示已启用,但暂未实现区域框绘制功能");
|
// 由于DeviceManager没有V8属性,暂时跳过区域框的绘制
|
||||||
|
// 注意:在实际应用中,应该通过正确的API获取区域位置信息
|
||||||
|
Console.WriteLine("区域温度显示已启用,但暂未实现区域框绘制功能");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"绘制区域框时发生异常: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
// 准备温度文本
|
||||||
|
List<string> temperatureTexts = new List<string>();
|
||||||
|
if (_showAverageTemperature)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"绘制区域框时发生异常: {ex.Message}");
|
temperatureTexts.Add($"平均温度: {temperatureData.AverageTemperature:F2} °C");
|
||||||
|
}
|
||||||
|
if (_showMinTemperature)
|
||||||
|
{
|
||||||
|
temperatureTexts.Add($"最低温度: {temperatureData.MinTemperature:F2} °C");
|
||||||
|
}
|
||||||
|
if (_showMaxTemperature)
|
||||||
|
{
|
||||||
|
temperatureTexts.Add($"最高温度: {temperatureData.MaxTemperature:F2} °C");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 准备温度文本
|
// 如果没有要显示的温度文本,直接返回
|
||||||
List<string> temperatureTexts = new List<string>();
|
if (temperatureTexts.Count == 0)
|
||||||
if (_showAverageTemperature)
|
return;
|
||||||
{
|
|
||||||
temperatureTexts.Add($"平均温度: {temperatureData.AverageTemperature:F2} °C");
|
|
||||||
}
|
|
||||||
if (_showMinTemperature)
|
|
||||||
{
|
|
||||||
temperatureTexts.Add($"最低温度: {temperatureData.MinTemperature:F2} °C");
|
|
||||||
}
|
|
||||||
if (_showMaxTemperature)
|
|
||||||
{
|
|
||||||
temperatureTexts.Add($"最高温度: {temperatureData.MaxTemperature:F2} °C");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有要显示的温度文本,直接返回
|
// 设置文本样式
|
||||||
if (temperatureTexts.Count == 0)
|
Font font = new Font("微软雅黑", 12, FontStyle.Bold);
|
||||||
return;
|
Brush brush = new SolidBrush(Color.White);
|
||||||
|
StringFormat format = new StringFormat();
|
||||||
|
format.Alignment = StringAlignment.Near; // 左对齐
|
||||||
|
format.LineAlignment = StringAlignment.Center;
|
||||||
|
|
||||||
// 设置文本样式
|
// 计算文本区域大小
|
||||||
Font font = new Font("微软雅黑", 12, FontStyle.Bold);
|
SizeF[] textSizes = new SizeF[temperatureTexts.Count];
|
||||||
Brush brush = new SolidBrush(Color.White);
|
float maxTextWidth = 0;
|
||||||
StringFormat format = new StringFormat();
|
float totalTextHeight = 0;
|
||||||
format.Alignment = StringAlignment.Near; // 左对齐
|
|
||||||
format.LineAlignment = StringAlignment.Center;
|
|
||||||
|
|
||||||
// 计算文本区域大小
|
|
||||||
SizeF[] textSizes = new SizeF[temperatureTexts.Count];
|
|
||||||
float maxTextWidth = 0;
|
|
||||||
float totalTextHeight = 0;
|
|
||||||
for (int i = 0; i < temperatureTexts.Count; i++)
|
|
||||||
{
|
|
||||||
textSizes[i] = g.MeasureString(temperatureTexts[i], font);
|
|
||||||
maxTextWidth = Math.Max(maxTextWidth, textSizes[i].Width);
|
|
||||||
totalTextHeight += textSizes[i].Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加文本间距
|
|
||||||
totalTextHeight += (temperatureTexts.Count - 1) * 5; // 5像素行间距
|
|
||||||
|
|
||||||
// 9. 如果是全局温度时,最低温度和最高温度、平均温度,显示三行(左对齐),整体水平和垂直相对于图像框居中显示
|
|
||||||
if (isGlobalTemperatureMode)
|
|
||||||
{
|
|
||||||
// 计算文本区域的位置(整体居中)
|
|
||||||
float textAreaX = (_imageBuffer.Width - maxTextWidth) / 2;
|
|
||||||
float textAreaY = (_imageBuffer.Height - totalTextHeight) / 2;
|
|
||||||
|
|
||||||
// 绘制温度文本
|
|
||||||
float currentY = textAreaY;
|
|
||||||
for (int i = 0; i < temperatureTexts.Count; i++)
|
for (int i = 0; i < temperatureTexts.Count; i++)
|
||||||
{
|
{
|
||||||
g.DrawString(temperatureTexts[i], font, brush, textAreaX, currentY, format);
|
textSizes[i] = g.MeasureString(temperatureTexts[i], font);
|
||||||
currentY += textSizes[i].Height + 5; // 加上行间距
|
maxTextWidth = Math.Max(maxTextWidth, textSizes[i].Width);
|
||||||
|
totalTextHeight += textSizes[i].Height;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 10. 如果是区域温度时,最低温度和最高温度、平均温度,显示三行(左对齐)
|
|
||||||
// 由于无法获取区域框信息,临时使用全局居中显示
|
|
||||||
else if (_showAreaTemperature)
|
|
||||||
{
|
|
||||||
// 计算文本区域的位置(整体居中显示)
|
|
||||||
float textAreaX = (_imageBuffer.Width - maxTextWidth) / 2;
|
|
||||||
float textAreaY = (_imageBuffer.Height - totalTextHeight) / 2;
|
|
||||||
|
|
||||||
// 绘制温度文本
|
// 添加文本间距
|
||||||
float currentY = textAreaY;
|
totalTextHeight += (temperatureTexts.Count - 1) * 5; // 5像素行间距
|
||||||
for (int i = 0; i < temperatureTexts.Count; i++)
|
|
||||||
|
// 9. 如果是全局温度时,最低温度和最高温度、平均温度,显示三行(左对齐),整体水平和垂直相对于图像框居中显示
|
||||||
|
if (isGlobalTemperatureMode)
|
||||||
{
|
{
|
||||||
g.DrawString(temperatureTexts[i], font, brush, textAreaX, currentY, format);
|
// 计算文本区域的位置(整体居中)
|
||||||
currentY += textSizes[i].Height + 5; // 加上行间距
|
float textAreaX = (_displayImage.Width - maxTextWidth) / 2;
|
||||||
|
float textAreaY = (_displayImage.Height - totalTextHeight) / 2;
|
||||||
|
|
||||||
|
// 绘制温度文本
|
||||||
|
float currentY = textAreaY;
|
||||||
|
for (int i = 0; i < temperatureTexts.Count; i++)
|
||||||
|
{
|
||||||
|
g.DrawString(temperatureTexts[i], font, brush, textAreaX, currentY, format);
|
||||||
|
currentY += textSizes[i].Height + 5; // 加上行间距
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// 10. 如果是区域温度时,最低温度和最高温度、平均温度,显示三行(左对齐)
|
||||||
|
// 由于无法获取区域框信息,临时使用全局居中显示
|
||||||
|
else if (_showAreaTemperature)
|
||||||
|
{
|
||||||
|
// 计算文本区域的位置(整体居中显示)
|
||||||
|
float textAreaX = (_displayImage.Width - maxTextWidth) / 2;
|
||||||
|
float textAreaY = (_displayImage.Height - totalTextHeight) / 2;
|
||||||
|
|
||||||
|
// 绘制温度文本
|
||||||
|
float currentY = textAreaY;
|
||||||
|
for (int i = 0; i < temperatureTexts.Count; i++)
|
||||||
|
{
|
||||||
|
g.DrawString(temperatureTexts[i], font, brush, textAreaX, currentY, format);
|
||||||
|
currentY += textSizes[i].Height + 5; // 加上行间距
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放资源
|
||||||
|
font.Dispose();
|
||||||
|
brush.Dispose();
|
||||||
|
format.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 释放资源
|
// 设置显示状态标志
|
||||||
font.Dispose();
|
_isDisplayingInfo = true;
|
||||||
brush.Dispose();
|
|
||||||
format.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记信息正在显示
|
// 标记信息正在显示
|
||||||
|
|||||||
@@ -15,20 +15,20 @@
|
|||||||
3. Ping通状态变化时,修改Ping状态,调用更新Info
|
3. Ping通状态变化时,修改Ping状态,调用更新Info
|
||||||
4. 图像更新时,保存LastImage,调用更新UI
|
4. 图像更新时,保存LastImage,调用更新UI
|
||||||
5. 2-4 只在非暂停状态下调用更新,暂停状态下不更新Info和UI
|
5. 2-4 只在非暂停状态下调用更新,暂停状态下不更新Info和UI
|
||||||
6. 数据显示菜单勾选变化时,调用实时显示
|
6. 数据显示菜单勾选变化时,调用更新实时信息
|
||||||
|
|
||||||
### 更新Info
|
### 更新Info
|
||||||
1. 以透明色清空Info
|
1. 以透明色清空Info
|
||||||
2. 如果暂停,显示暂停信息,否则如果Ping不通或断开,显示重连信息,否则就绪
|
2. 如果暂停,显示暂停信息,否则如果Ping不通或断开,显示重连信息,否则就绪
|
||||||
3. 如果未就绪,调用更新UI,否则不调用实时显示
|
3. 如果未就绪,调用更新UI
|
||||||
|
|
||||||
### 更新UI
|
### 更新UI
|
||||||
1. 先将LastImage绘制到全局缓冲
|
1. 先将LastImage绘制到全局缓冲
|
||||||
2. 再将InfoImage绘制到缓冲
|
2. 再将InfoImage绘制到缓冲
|
||||||
3. 在就绪条件下,将Display绘制到缓冲
|
3. 在就绪条件下,调用更新实时信息,并将DisplayImage绘制到缓冲
|
||||||
4. 最后一次性绘制到图像框的bitmap
|
4. 最后一次性绘制到图像框的bitmap
|
||||||
|
|
||||||
### 实时显示
|
### 更新实时信息
|
||||||
1. 以透明色清空DisplayImage
|
1. 以透明色清空DisplayImage
|
||||||
2. 如果没有温度数据或温度数据的时间3秒之前,返回
|
2. 如果没有温度数据或温度数据的时间3秒之前,返回
|
||||||
3. 温度显示菜单下如果未勾选区域温度和全局温度,则不显示任何温度信息
|
3. 温度显示菜单下如果未勾选区域温度和全局温度,则不显示任何温度信息
|
||||||
|
|||||||
Reference in New Issue
Block a user