编辑
2025-02-22
C# 应用
00
请注意,本文编写于 73 天前,最后修改于 73 天前,其中某些信息可能已经过时。

目录

简介
实现代码
核心属性设计:
主要绘制逻辑(OnPaint方法)分为三个部分
总结

简介

本文将详细介绍如何使用C#和GDI+技术实现一个自定义的温度计控件。这个控件具有以下特点:

  • 可视化温度显示
  • 可自定义最大最小温度值
  • 支持动态更新温度
  • 具有平滑的动画效果
  • 支持自定义颜色主题

实现代码

image.png

首先,创建一个继承自Control的自定义控件类:

C#
using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppControls { public class ThermometerControl : Control { // 温度相关属性 private float _currentTemperature = 0; private float _minTemperature = -20; private float _maxTemperature = 50; // 尺寸相关属性 private int _bulbRadius = 20; // 颜色设置 private Color _mercuryColor = Color.Red; private Color _backgroundColor = Color.White; private Color _borderColor = Color.Black; // 控件尺寸常量 private const int TUBE_WIDTH = 10; private const int SCALE_LENGTH = 5; private const int LEFT_MARGIN = 15; private const int BOTTOM_MARGIN = 25; // 球形底部半径属性 public int BulbRadius { get => _bulbRadius; set { if (value != _bulbRadius && value >= 10 && value <= 50) // 设置合理的范围限制 { _bulbRadius = value; UpdateControlSize(); Invalidate(); } } } // 温度相关属性 public float CurrentTemperature { get => _currentTemperature; set { if (value != _currentTemperature) { _currentTemperature = Math.Max(_minTemperature, Math.Min(_maxTemperature, value)); Invalidate(); } } } public float MinTemperature { get => _minTemperature; set { if (value != _minTemperature) { _minTemperature = value; Invalidate(); } } } public float MaxTemperature { get => _maxTemperature; set { if (value != _maxTemperature) { _maxTemperature = value; Invalidate(); } } } // 颜色属性 public Color MercuryColor { get => _mercuryColor; set { if (value != _mercuryColor) { _mercuryColor = value; Invalidate(); } } } public Color BackgroundColor { get => _backgroundColor; set { if (value != _backgroundColor) { _backgroundColor = value; Invalidate(); } } } public Color BorderColor { get => _borderColor; set { if (value != _borderColor) { _borderColor = value; Invalidate(); } } } public ThermometerControl() { SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true); UpdateControlSize(); } // 更新控件尺寸 private void UpdateControlSize() { // 根据球形底部半径计算合适的控件尺寸 int minWidth = LEFT_MARGIN + _bulbRadius * 2 + SCALE_LENGTH + 35; // 35为刻度文本预留空间 int minHeight = _bulbRadius * 4 + BOTTOM_MARGIN; // 确保有足够空间显示温度计管体 MinimumSize = new Size(minWidth, minHeight); if (Width < minWidth) Width = minWidth; if (Height < minHeight) Height = minHeight; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; // 计算关键尺寸 int bulbCenterX = LEFT_MARGIN + _bulbRadius; int bulbCenterY = Height - BOTTOM_MARGIN - _bulbRadius; int tubeHeight = Height - 2 * _bulbRadius - BOTTOM_MARGIN; int tubeTop = _bulbRadius; // 绘制温度计外壳 DrawThermometerBody(g, bulbCenterX, bulbCenterY, tubeHeight); // 绘制水银柱 DrawMercury(g, bulbCenterX, bulbCenterY, tubeHeight); // 绘制刻度 DrawScale(g, bulbCenterX, tubeTop, tubeHeight); } private void DrawThermometerBody(Graphics g, int bulbCenterX, int bulbCenterY, int tubeHeight) { using (Pen borderPen = new Pen(_borderColor, 2)) { // 绘制管子 g.DrawLine(borderPen, bulbCenterX - TUBE_WIDTH / 2, _bulbRadius, bulbCenterX - TUBE_WIDTH / 2, bulbCenterY); g.DrawLine(borderPen, bulbCenterX + TUBE_WIDTH / 2, _bulbRadius, bulbCenterX + TUBE_WIDTH / 2, bulbCenterY); // 绘制球形底部 g.DrawEllipse(borderPen, bulbCenterX - _bulbRadius, bulbCenterY - _bulbRadius, _bulbRadius * 2, _bulbRadius * 2); } // 填充球形底部背景 using (SolidBrush bulbBrush = new SolidBrush(_backgroundColor)) { g.FillEllipse(bulbBrush, bulbCenterX - _bulbRadius + 1, bulbCenterY - _bulbRadius + 1, (_bulbRadius - 1) * 2, (_bulbRadius - 1) * 2); } } private void DrawMercury(Graphics g, int bulbCenterX, int bulbCenterY, int tubeHeight) { float temperatureRange = _maxTemperature - _minTemperature; float temperatureHeight = (_currentTemperature - _minTemperature) / temperatureRange; int mercuryHeight = (int)(tubeHeight * temperatureHeight); using (SolidBrush mercuryBrush = new SolidBrush(_mercuryColor)) { // 填充管中的水银 g.FillRectangle(mercuryBrush, bulbCenterX - TUBE_WIDTH / 2 + 2, bulbCenterY - mercuryHeight, TUBE_WIDTH - 3, mercuryHeight); // 填充球部的水银 g.FillEllipse(mercuryBrush, bulbCenterX - _bulbRadius + 2, bulbCenterY - _bulbRadius + 2, (_bulbRadius - 2) * 2, (_bulbRadius - 2) * 2); } } private void DrawScale(Graphics g, int centerX, int topY, int height) { using (Pen scalePen = new Pen(_borderColor, 1)) using (Font scaleFont = new Font("Arial", 8)) using (StringFormat sf = new StringFormat { Alignment = StringAlignment.Near }) { int scaleCount = 10; float temperatureStep = (_maxTemperature - _minTemperature) / scaleCount; float pixelStep = height / (float)scaleCount; for (int i = 0; i <= scaleCount; i++) { int y = topY + (int)(i * pixelStep); // 绘制刻度线 g.DrawLine(scalePen, centerX + TUBE_WIDTH / 2, y, centerX + TUBE_WIDTH / 2 + SCALE_LENGTH, y); // 绘制温度值 float temperature = _maxTemperature - i * temperatureStep; g.DrawString( temperature.ToString("F0") + "°", scaleFont, Brushes.Black, new RectangleF( centerX + TUBE_WIDTH / 2 + SCALE_LENGTH + 2, y - 6, 30, 12), sf); } } } } }

核心属性设计:

  • 温度相关属性:当前温度(_currentTemperature)、最小温度(_minTemperature)、最大温度(_maxTemperature)
  • 外观属性:球部半径(_bulbRadius)、水银颜色(_mercuryColor)、背景色(_backgroundColor)、边框色(_borderColor)
  • 控件尺寸常量:管宽(TUBE_WIDTH)、刻度长度(SCALE_LENGTH)等

主要绘制逻辑(OnPaint方法)分为三个部分

C#
DrawThermometerBody() // 绘制温度计外壳 DrawMercury() // 绘制水银柱 DrawScale() // 绘制刻度

总结

这个温度计控件实现了基本的温度显示功能,具有良好的可扩展性和自定义性。通过GDI+绘图技术,我们实现了平滑的显示效果和专业的外观。该控件可以用于各种需要温度显示的应用场景,如天气站、工业控制等领域。

本文作者:rick

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!