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

目录

控件特性
核心实现
1. 基础架构
2. 视觉定制选项
3. 动画系统
4. 绘制过程
完整代码
总结

在WinForm应用程序开发中,一个富有视觉吸引力的用户界面往往能够提升用户体验。今天,我将为大家介绍一个自定义的水波进度控件(WaveProgressControl),它不仅功能强大,还具有出色的视觉效果。

控件特性

  • 流畅的水波动画效果
  • 渐变色水波
  • 可自定义的边框样式
  • 阴影和高光效果
  • 实时进度显示
  • 丰富的自定义选项

核心实现

1. 基础架构

C#
public class WaveProgressControl : Control { private float _progress = 0f; private float _targetProgress = 0f; private Timer _animationTimer; private Timer _waveTimer; private float _waveOffset = 0f; }

控件继承自基础Control类,通过两个Timer实现水波动画和进度变化的平滑过渡。

2. 视觉定制选项

控件提供了丰富的自定义选项,包括:

  • 水波颜色(双色渐变)
  • 边框样式(颜色、宽度、线型)
  • 阴影效果
  • 高光效果
  • 文本颜色

3. 动画系统

C#
private void InitializeTimers() { _animationTimer = new Timer(); _animationTimer.Interval = 16; _animationTimer.Tick += (s, e) => { if (Math.Abs(_progress - _targetProgress) > 0.001f) { _progress += (_targetProgress - _progress) * ANIMATION_SPEED; Invalidate(); } }; _animationTimer.Start(); _waveTimer = new Timer(); _waveTimer.Interval = 16; _waveTimer.Tick += (s, e) => { _waveOffset += 0.1f; if (_waveOffset > Math.PI * 2) _waveOffset = 0; Invalidate(); }; _waveTimer.Start(); }

采用双Timer机制:

  • animationTimer负责进度值的平滑过渡
  • waveTimer控制水波动画效果

4. 绘制过程

控件的绘制过程分为几个关键步骤:

阴影效果

C#
// 绘制阴影效果 if (EnableShade) { using (GraphicsPath shadowPath = new GraphicsPath()) { shadowPath.AddEllipse(circleRect); using (PathGradientBrush shadowBrush = new PathGradientBrush(shadowPath)) { shadowBrush.CenterColor = ShadeColor; shadowBrush.SurroundColors = new Color[] { Color.Transparent }; e.Graphics.FillPath(shadowBrush, shadowPath); } } }

边框绘制

C#
// 绘制外圆 if (ShowBorder) { using (GraphicsPath borderPath = new GraphicsPath()) { borderPath.AddEllipse(circleRect); using (Pen borderPen = new Pen(BorderColor, BorderWidth)) { borderPen.DashStyle = BorderStyle; e.Graphics.DrawPath(borderPen, borderPath); } } }

水波效果

C#
// 绘制水波 int waveBottom = (int)(circleRect.Bottom - (circleRect.Height * currentProgress)); using (GraphicsPath wavePath = new GraphicsPath()) { Point[] points = new Point[circleRect.Width + 3]; for (int x = 0; x <= circleRect.Width; x++) { int y = (int)(Math.Sin(x * 0.05f + _waveOffset) * WAVE_HEIGHT); points[x] = new Point(x + circleRect.X, waveBottom + y); } points[points.Length - 2] = new Point(circleRect.Right, circleRect.Bottom); points[points.Length - 1] = new Point(circleRect.Left, circleRect.Bottom); wavePath.AddLines(points); using (LinearGradientBrush brush = new LinearGradientBrush( circleRect, WaveColor1, WaveColor2, 90f)) { e.Graphics.FillPath(brush, wavePath); } }

高光效果

C#
// 绘制高光效果 if (EnableHighlight) { using (LinearGradientBrush highlightBrush = new LinearGradientBrush( circleRect, HighlightColor, Color.Transparent, 45f)) { e.Graphics.FillEllipse(highlightBrush, circleRect); } }

完整代码

C#
using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using Timer = System.Windows.Forms.Timer; [ToolboxItem(true)] [Description("水波浪进度控件")] public class WaveProgressControl : Control { private float _progress = 0f; private float _targetProgress = 0f; private Timer _animationTimer; private Timer _waveTimer; private float _waveOffset = 0f; private const float WAVE_HEIGHT = 10f; private const float ANIMATION_SPEED = 0.02f; #region 属性定义 // 基本属性 private Color _waveColor1 = Color.FromArgb(100, 181, 246); private Color _waveColor2 = Color.FromArgb(33, 150, 243); private Color _borderColor = Color.FromArgb(200, 200, 200); private float _borderWidth = 2f; private DashStyle _borderStyle = DashStyle.Solid; private bool _enableShade = true; private Color _shadeColor = Color.FromArgb(30, 0, 0, 0); private bool _enableHighlight = true; private Color _highlightColor = Color.FromArgb(30, 255, 255, 255); private Color _textColor = Color.FromArgb(64, 64, 64); private bool _showBorder = true; [Category("Appearance")] [Description("第一个波浪颜色")] public Color WaveColor1 { get => _waveColor1; set { _waveColor1 = value; Invalidate(); } } [Category("Appearance")] [Description("第二个波浪颜色")] public Color WaveColor2 { get => _waveColor2; set { _waveColor2 = value; Invalidate(); } } [Category("Border")] [Description("边框颜色")] public Color BorderColor { get => _borderColor; set { _borderColor = value; Invalidate(); } } [Category("Border")] [Description("边框宽度")] public float BorderWidth { get => _borderWidth; set { _borderWidth = value; Invalidate(); } } [Category("Border")] [Description("边框样式")] public DashStyle BorderStyle { get => _borderStyle; set { _borderStyle = value; Invalidate(); } } [Category("Border")] [Description("是否显示边框")] public bool ShowBorder { get => _showBorder; set { _showBorder = value; Invalidate(); } } [Category("Effects")] [Description("启用阴影效果")] public bool EnableShade { get => _enableShade; set { _enableShade = value; Invalidate(); } } [Category("Effects")] [Description("阴影颜色")] public Color ShadeColor { get => _shadeColor; set { _shadeColor = value; Invalidate(); } } [Category("Effects")] [Description("启用高光效果")] public bool EnableHighlight { get => _enableHighlight; set { _enableHighlight = value; Invalidate(); } } [Category("Effects")] [Description("高光颜色")] public Color HighlightColor { get => _highlightColor; set { _highlightColor = value; Invalidate(); } } [Category("Appearance")] [Description("文本颜色")] public Color TextColor { get => _textColor; set { _textColor = value; Invalidate(); } } [Category("Behavior")] [Description("当前进度值(0-1)")] [DefaultValue(0f)] public float Progress { get => _targetProgress; set { if (value < 0f) value = 0f; if (value > 1f) value = 1f; _targetProgress = value; } } #endregion public WaveProgressControl() { Size = new Size(100, 100); SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true); if (!DesignMode) { InitializeTimers(); } } private void InitializeTimers() { _animationTimer = new Timer(); _animationTimer.Interval = 16; _animationTimer.Tick += (s, e) => { if (Math.Abs(_progress - _targetProgress) > 0.001f) { _progress += (_targetProgress - _progress) * ANIMATION_SPEED; Invalidate(); } }; _animationTimer.Start(); _waveTimer = new Timer(); _waveTimer.Interval = 16; _waveTimer.Tick += (s, e) => { _waveOffset += 0.1f; if (_waveOffset > Math.PI * 2) _waveOffset = 0; Invalidate(); }; _waveTimer.Start(); } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); if (!DesignMode) { InitializeTimers(); } } protected override void OnHandleDestroyed(EventArgs e) { if (!DesignMode) { _animationTimer?.Stop(); _waveTimer?.Stop(); } base.OnHandleDestroyed(e); } protected override void OnPaint(PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.SmoothingMode = SmoothingMode.HighQuality; e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; e.Graphics.CompositingQuality = CompositingQuality.HighQuality; int size = Math.Min(Width, Height); int padding = 10; Rectangle circleRect = new Rectangle(padding, padding, size - padding * 2, size - padding * 2); // 计算当前进度 float currentProgress = DesignMode ? Progress : _progress; // 绘制阴影效果 if (EnableShade) { using (GraphicsPath shadowPath = new GraphicsPath()) { shadowPath.AddEllipse(circleRect); using (PathGradientBrush shadowBrush = new PathGradientBrush(shadowPath)) { shadowBrush.CenterColor = ShadeColor; shadowBrush.SurroundColors = new Color[] { Color.Transparent }; e.Graphics.FillPath(shadowBrush, shadowPath); } } } // 绘制外圆 if (ShowBorder) { using (GraphicsPath borderPath = new GraphicsPath()) { borderPath.AddEllipse(circleRect); using (Pen borderPen = new Pen(BorderColor, BorderWidth)) { borderPen.DashStyle = BorderStyle; e.Graphics.DrawPath(borderPen, borderPath); } } } // 创建圆形裁剪区域 using (GraphicsPath clipPath = new GraphicsPath()) { clipPath.AddEllipse(circleRect); e.Graphics.SetClip(clipPath); // 绘制水波 int waveBottom = (int)(circleRect.Bottom - (circleRect.Height * currentProgress)); using (GraphicsPath wavePath = new GraphicsPath()) { Point[] points = new Point[circleRect.Width + 3]; for (int x = 0; x <= circleRect.Width; x++) { int y = (int)(Math.Sin(x * 0.05f + _waveOffset) * WAVE_HEIGHT); points[x] = new Point(x + circleRect.X, waveBottom + y); } points[points.Length - 2] = new Point(circleRect.Right, circleRect.Bottom); points[points.Length - 1] = new Point(circleRect.Left, circleRect.Bottom); wavePath.AddLines(points); using (LinearGradientBrush brush = new LinearGradientBrush( circleRect, WaveColor1, WaveColor2, 90f)) { e.Graphics.FillPath(brush, wavePath); } } // 绘制高光效果 if (EnableHighlight) { using (LinearGradientBrush highlightBrush = new LinearGradientBrush( circleRect, HighlightColor, Color.Transparent, 45f)) { e.Graphics.FillEllipse(highlightBrush, circleRect); } } e.Graphics.ResetClip(); } // 绘制百分比文本 string percentText = $"{(currentProgress * 100):F0}%"; using (Font font = new Font("Arial", size / 8)) { SizeF textSize = e.Graphics.MeasureString(percentText, font); PointF textPos = new PointF( circleRect.X + (circleRect.Width - textSize.Width) / 2, circleRect.Y + (circleRect.Height - textSize.Height) / 2 ); using (Brush textBrush = new SolidBrush(TextColor)) { e.Graphics.DrawString(percentText, font, textBrush, textPos); } } base.OnPaint(e); } protected override void Dispose(bool disposing) { if (disposing) { _animationTimer?.Dispose(); _waveTimer?.Dispose(); } base.Dispose(disposing); } }

image.png

总结

这个水波进度控件不仅提供了醒目的视觉效果,还具有良好的可定制性和性能表现。它适用于需要展示进度信息的各种场景,能够为您的WinForm应用增添一份独特的视觉魅力。

希望这个控件能为您的项目锦上添花。如有任何问题或建议,欢迎讨论交流!

本文作者:rick

本文链接:

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