diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs index dc5eb06..d55d1a3 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs @@ -31,6 +31,10 @@ namespace JoyD.Windows.CS.Toprie // 信息图像,用于显示额外信息 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"); } + // 初始化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为透明 if (imageBox != null && !imageBox.IsDisposed) { @@ -771,50 +786,17 @@ namespace JoyD.Windows.CS.Toprie } } - // 步骤3:在就绪条件下,如果有温度数据(时间在最近3秒内),显示最高温度(居中显示) - if (!_isPaused && IsDevicePingable && _deviceManager != null && _deviceManager.ConnectionStatus == ConnectionStatus.Connected) + // 步骤2.1:绘制DisplayImage(实时温度信息等) + lock (_displayImageLock) { - TemperatureData temperatureData = _deviceManager.LastTemperature; - if (temperatureData != null && temperatureData.Timestamp != null) + if (_displayImage != null) { - // 检查温度数据时间是否在最近3秒内 - 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); - } - } + g.DrawImage(_displayImage, 0, 0); } } + + // 注意:温度信息不再直接在这里绘制 + // 而是在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) { @@ -1853,125 +1853,131 @@ namespace JoyD.Windows.CS.Toprie /// private void UpdateRealTimeInfoOnUI() { - // 1. 以透明色清空图像缓冲区的温度显示区域 - // 遵循README要求:中途不进行Dispose和设置为null,只在上面进行绘制 - if (_imageBuffer == null) - return; - - using (Graphics g = Graphics.FromImage(_imageBuffer)) + lock (_displayImageLock) { - // 清除DisplayImage为透明色 - g.Clear(Color.Transparent); - - // 2. 如果没有温度数据或温度数据的时间3秒之前,返回 - TemperatureData temperatureData = _deviceManager.LastTemperature; - if (temperatureData == null || temperatureData.Timestamp == null) + // 1. 以透明色清空DisplayImage + // 遵循README要求:中途不进行Dispose和设置为null,只在上面进行绘制 + if (_displayImage == 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) + using (Graphics g = Graphics.FromImage(_displayImage)) { - 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属性,暂时跳过区域框的绘制 - // 注意:在实际应用中,应该通过正确的API获取区域位置信息 - Console.WriteLine("区域温度显示已启用,但暂未实现区域框绘制功能"); + try + { + // 由于DeviceManager没有V8属性,暂时跳过区域框的绘制 + // 注意:在实际应用中,应该通过正确的API获取区域位置信息 + Console.WriteLine("区域温度显示已启用,但暂未实现区域框绘制功能"); + } + catch (Exception ex) + { + Console.WriteLine($"绘制区域框时发生异常: {ex.Message}"); + } } - catch (Exception ex) + + // 准备温度文本 + List temperatureTexts = new List(); + 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 temperatureTexts = new List(); - if (_showAverageTemperature) - { - 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) + return; - // 如果没有要显示的温度文本,直接返回 - if (temperatureTexts.Count == 0) - return; + // 设置文本样式 + Font font = new Font("微软雅黑", 12, FontStyle.Bold); + 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); - Brush brush = new SolidBrush(Color.White); - StringFormat format = new StringFormat(); - 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; + // 计算文本区域大小 + SizeF[] textSizes = new SizeF[temperatureTexts.Count]; + float maxTextWidth = 0; + float totalTextHeight = 0; for (int i = 0; i < temperatureTexts.Count; i++) { - g.DrawString(temperatureTexts[i], font, brush, textAreaX, currentY, format); - currentY += textSizes[i].Height + 5; // 加上行间距 + textSizes[i] = g.MeasureString(temperatureTexts[i], font); + 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; - for (int i = 0; i < temperatureTexts.Count; i++) + // 添加文本间距 + totalTextHeight += (temperatureTexts.Count - 1) * 5; // 5像素行间距 + + // 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; - // 释放资源 - font.Dispose(); - brush.Dispose(); - format.Dispose(); + // 绘制温度文本 + 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(); + } + + // 设置显示状态标志 + _isDisplayingInfo = true; } - + // 标记信息正在显示 _isDisplayingInfo = true; } diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/README.md b/Windows/CS/Framework4.0/Toprie/Toprie/README.md index 53b15d8..49e6874 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/README.md +++ b/Windows/CS/Framework4.0/Toprie/Toprie/README.md @@ -15,20 +15,20 @@ 3. Ping通状态变化时,修改Ping状态,调用更新Info 4. 图像更新时,保存LastImage,调用更新UI 5. 2-4 只在非暂停状态下调用更新,暂停状态下不更新Info和UI -6. 数据显示菜单勾选变化时,调用实时显示 +6. 数据显示菜单勾选变化时,调用更新实时信息 ### 更新Info 1. 以透明色清空Info 2. 如果暂停,显示暂停信息,否则如果Ping不通或断开,显示重连信息,否则就绪 -3. 如果未就绪,调用更新UI,否则不调用实时显示 +3. 如果未就绪,调用更新UI ### 更新UI 1. 先将LastImage绘制到全局缓冲 2. 再将InfoImage绘制到缓冲 -3. 在就绪条件下,将Display绘制到缓冲 +3. 在就绪条件下,调用更新实时信息,并将DisplayImage绘制到缓冲 4. 最后一次性绘制到图像框的bitmap -### 实时显示 +### 更新实时信息 1. 以透明色清空DisplayImage 2. 如果没有温度数据或温度数据的时间3秒之前,返回 3. 温度显示菜单下如果未勾选区域温度和全局温度,则不显示任何温度信息