利用Winform实现电压表或电流表

本文的内容是搬运而来,还是国外的资源容易获取,不像国内的,遮遮掩掩,各种想让你掏钱。本文内容仅作收集,无聊时学习收集到的资料,无其它作用

内容搬运链接:

Analog Meter (Ammeter/Voltmeter/etc) Control for C# and .NET « Random thoughts along the roadside…

测试环境:

visual studio 2017 

.net framework 4.0

效果图如下

步骤如下:

1  新建名为WinformDemo1的winform项目,.net framework选择4.0

2  新建名为AnalogMeterControl的类,并编辑如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WinformDemo1
{
	/// <summary>
	/// 下载链接:http://www.virtualroadside.com/blog/index.php/2008/01/18/analog-meter-ammetervoltmeteretc-control-for-c-and-net/
	/// http://www.virtualroadside.com/software/
	/// </summary>
	public class AnalogMeterControl : System.Windows.Forms.UserControl
	{

		Bitmap bgImage = null;
		Graphics realGraphics = null;

		/// <summary>
		/// 构造方法
		/// </summary>
		public AnalogMeterControl()
		{
			BackColor = Color.White;
			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			SetStyle(ControlStyles.UserPaint, true);
		}

		float r1x;
		float r1y;

		/// <summary>
		/// This does all of the drawing, but it definitely could
		/// be optimized... the biggest one is that the value
		/// could be drawn seperately from this, since thats the value
		/// that would probably be updated the most.
		/// </summary>
		private void CreateBackground()
		{

			float i;

			if (Width < 1 || Height < 1)
				return;

			Bitmap bmp = new Bitmap(Width, Height);
			Graphics g = Graphics.FromImage(bmp);
			g.SmoothingMode = SmoothingMode.HighQuality;

			// frame
			using (Brush b = new SolidBrush(frameColor))
			{
				g.FillRectangle(b, ClientRectangle);
			}

			Rectangle meterLocation;

			// setup a clip rectangle for the meter itself
			if (stretch)
				meterLocation = new Rectangle(framePadding.Left, framePadding.Top, Width - framePadding.Horizontal, Height - framePadding.Vertical);
			else
				meterLocation = new Rectangle(framePadding.Left, framePadding.Top, Width - framePadding.Horizontal, internalPadding.Vertical + Width / 2 - framePadding.Top);

			// set the clip rectangle
			g.IntersectClip(meterLocation);

			// fill meter with its background
			using (Brush b = new SolidBrush(BackColor))
			{
				g.FillRectangle(b, meterLocation);
			}

			// 1 is outer point, 2 is inner point
			r1x = (float)(meterLocation.Width - internalPadding.Horizontal) / 2;
			r1y = (float)(meterLocation.Height - internalPadding.Vertical);
			float r2x;
			float r2y;

			// draw tiny ticks
			if (tickTinyFrequency > 0)
			{
				using (Pen p = new Pen(ForeColor, tickTinyWidth))
				{

					r2x = r1x - tickTinySize;
					r2y = r1y - tickTinySize;

					for (i = minValue; i <= maxValue; i += tickTinyFrequency)
					{
						if ((tickSmallFrequency > 0 && (i - minValue) % tickSmallFrequency == 0) || (tickLargeFrequency > 0 && (i - minValue) % tickLargeFrequency == 0))
							continue;
						PointF[] pts = GetLine(i, r1x, r1y, r2x, r2y);
						g.DrawLine(p, pts[0], pts[1]);
					}
				}
			}

			// draw small ticks
			if (tickSmallFrequency > 0)
			{
				using (Pen p = new Pen(ForeColor, tickSmallWidth))
				{

					r2x = r1x - tickSmallSize;
					r2y = r1y - tickSmallSize;

					for (i = minValue; i <= maxValue; i += tickSmallFrequency)
					{
						if (tickLargeFrequency > 0 && (i - minValue) % tickLargeFrequency == 0)
							continue;
						PointF[] pts = GetLine(i, r1x, r1y, r2x, r2y);
						g.DrawLine(p, pts[0], pts[1]);
					}
				}
			}

			// draw large ticks and numbers
			if (tickLargeFrequency > 0)
			{
				using (Pen p = new Pen(ForeColor, tickLargeWidth))
				{

					r2x = r1x - tickLargeSize;
					r2y = r1y - tickLargeSize;

					float r3x = r2x - Font.Height;
					float r3y = r2y - Font.Height;

					for (i = minValue; i <= maxValue; i += tickLargeFrequency)
					{
						PointF[] pts = GetLine(i, r1x, r1y, r2x, r2y);
						g.DrawLine(p, pts[0], pts[1]);

						SizeF sz = g.MeasureString(i.ToString(), Font);
						pts = GetLine(i, r1x, r1y, r3x, r3y);
						g.DrawString(i.ToString(), Font, p.Brush, pts[1].X - sz.Width / 2, pts[1].Y - sz.Height / 2);

					}
				}
			}

			// finally, the title
			if (Text != "")
			{
				using (Brush b = new SolidBrush(ForeColor))
				{
					SizeF sz = g.MeasureString(Text, Font);
					g.DrawString(Text, Font, b, framePadding.Left + (meterLocation.Width / 2) - sz.Width / 2, framePadding.Top + (meterLocation.Height * 3) / 4 - sz.Height / 2);
				}
			}

			g.Dispose();

			// done
			if (bgImage != null)
				bgImage.Dispose();

			bgImage = bmp;

			if (realGraphics != null)
				DrawMeter(realGraphics);
		}

		private PointF[] GetLine(float value, float r1x, float r1y, float r2x, float r2y)
		{

			PointF[] p = new PointF[2];

			float angle = ((value > maxValue ? maxValue : (value < minValue ? minValue : value)) - minValue) * (((float)Math.PI - tickStartAngle * 2) / (maxValue - minValue)) + tickStartAngle;

			// need to figure out where to calculate from

			p[0] = new PointF((float)(framePadding.Left + internalPadding.Left + (r1x - r1x * Math.Cos(angle))), (float)(framePadding.Top + internalPadding.Top + (r1y - r1y * Math.Sin(angle))));
			p[1] = new PointF((float)(framePadding.Left + internalPadding.Left + (r1x - r2x * Math.Cos(angle))), (float)(framePadding.Top + internalPadding.Top + (r1y - r2y * Math.Sin(angle))));

			return p;
		}

		private void DrawMeter(Graphics g)
		{

			g.DrawImageUnscaled(bgImage, 0, 0);

			// draw value -- this can be optimized, draw this outside of this routine
			using (Pen p = new Pen(pointerColor, tickLargeWidth))
			{
				PointF[] pts = GetLine(value, r1x, r1y, 0, 0);
				g.SmoothingMode = SmoothingMode.HighQuality;
				g.DrawLine(p, pts[0], pts[1]);
			}
		}

		/// <summary>
		/// Title to display on the meter
		/// </summary>
		[Category("Meter"), Description("Title to display on the meter")]
		public override string Text
		{
			get
			{
				return base.Text;
			}
			set
			{
				base.Text = value;
				CreateBackground();
			}
		}

		private float value = 0;

		/// <summary>
		/// 电压表的值
		/// </summary>
		[DefaultValue(0), Category("Meter"), Description("Value of meter")]
		public float Value
		{
			get { return this.value; }
			set
			{
				if (value != this.value)
				{
					this.value = value;
					DrawMeter(realGraphics);
				}
			}
		}


		private float maxValue = 15;

		/// <summary>
		/// 电压表的最大值(刻度最大值)
		/// </summary>
		[DefaultValue(15), Category("Meter"), Description("Maximum value of the meter")]
		public float MaxValue
		{
			get { return maxValue; }
			set
			{
				maxValue = value;
				CreateBackground();
			}
		}

		private float minValue = 0;

		/// <summary>
		/// 电压表的最小值(刻度最小值)
		/// </summary>
		[DefaultValue(0), Category("Meter"), Description("Minimum value of the meter")]
		public float MinValue
		{
			get { return minValue; }
			set
			{
				minValue = value;
				CreateBackground();
			}
		}

		private float tickTinyFrequency = 0.2F;

		/// <summary>
		/// Frequency of tiny ticks (0 to disable)
		/// </summary>
		[DefaultValue(0.2F), Category("Meter"), Description("Frequency of tiny ticks (0 to disable)")]
		public float TickTinyFrequency
		{
			get { return tickTinyFrequency; }
			set
			{
				tickTinyFrequency = value;
				CreateBackground();
			}
		}


		private float tickSmallFrequency = 1;

		/// <summary>
		/// Frequency of small ticks (0 to disable)
		/// </summary>
		[DefaultValue(1F), Category("Meter"), Description("Frequency of small ticks (0 to disable)")]
		public float TickSmallFrequency
		{
			get { return tickSmallFrequency; }
			set
			{
				tickSmallFrequency = value;
				CreateBackground();
			}
		}

		private float tickLargeFrequency = 5F;

		/// <summary>
		/// Frequency of large ticks (0 to disable)
		/// </summary>
		[DefaultValue(5F), Category("Meter"), Description("Frequency of large ticks (0 to disable)")]
		public float TickLargeFrequency
		{
			get { return tickLargeFrequency; }
			set
			{
				tickLargeFrequency = value;
				CreateBackground();
			}
		}

		private float tickTinyWidth = 1F;

		/// <summary>
		/// Stroke width of tiny ticks
		/// </summary>
		[DefaultValue(1F), Category("Meter"), Description("Stroke width of tiny ticks")]
		public float TickTinyWidth
		{
			get { return tickTinyWidth; }
			set
			{
				tickTinyWidth = value;
				CreateBackground();
			}
		}

		private float tickSmallWidth = 1F;

		/// <summary>
		/// Stroke width of small ticks
		/// </summary>
		[DefaultValue(1F), Category("Meter"), Description("Stroke width of small ticks")]
		public float TickSmallWidth
		{
			get { return tickSmallWidth; }
			set
			{
				tickSmallWidth = value;
				CreateBackground();
			}
		}

		private float tickLargeWidth = 2F;

		/// <summary>
		/// Stroke width of large ticks
		/// </summary>
		[DefaultValue(2F), Category("Meter"), Description("Stroke width of large ticks")]
		public float TickLargeWidth
		{
			get { return tickLargeWidth; }
			set
			{
				tickLargeWidth = value;
				CreateBackground();
			}
		}

		private float tickStartAngle = 20 * (float)(Math.PI / 180);

		/// <summary>
		/// Angle the meter starts display at in degrees
		/// </summary>
		[DefaultValue(20 * (float)(Math.PI / 180)), Category("Meter"), Description("Angle the meter starts display at in degrees")]
		public float TickStartAngle
		{
			get
			{
				return tickStartAngle * (float)(180 / Math.PI);
			}
			set
			{
				if (value < 0 || value > 75)
					throw new Exception("The angle must be between a value of 0 and 75 degrees");
				tickStartAngle = value * (float)(Math.PI / 180);
				CreateBackground();
			}
		}



		private float tickTinySize = 5F;

		/// <summary>
		/// Size of the tiny tick marks
		/// </summary>
		[DefaultValue(5F), Category("Meter")]
		public float TickTinySize
		{
			get { return tickTinySize; }
			set
			{
				tickTinySize = value;
				CreateBackground();
			}
		}


		private float tickSmallSize = 15F;

		/// <summary>
		/// Size of the small tick marks
		/// </summary>
		[DefaultValue(15F), Category("Meter")]
		public float TickSmallSize
		{
			get { return tickSmallSize; }
			set
			{
				tickSmallSize = value;
				CreateBackground();
			}
		}

		private float tickLargeSize = 20F;

		/// <summary>
		/// Size of the large tick marks
		/// </summary>
		[DefaultValue(20F), Category("Meter")]
		public float TickLargeSize
		{
			get { return tickLargeSize; }
			set
			{
				tickLargeSize = value;
				CreateBackground();
			}
		}

		/// <summary>
		/// Background color of the meter
		/// </summary>
		[DefaultValue(typeof(Color), "White")]
		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				base.BackColor = value;
				CreateBackground();
			}
		}

		/// <summary>
		/// Font of the control
		/// </summary>
		public override Font Font
		{
			get
			{
				return base.Font;
			}
			set
			{
				base.Font = value;
				CreateBackground();
			}
		}

		/// <summary>
		/// Color of tickmarks and text on meter
		/// </summary>
		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				base.ForeColor = value;
				CreateBackground();
			}
		}

		private Color pointerColor = Color.Red;

		/// <summary>
		/// Color of the primary pointer
		/// </summary>
		[DefaultValue(typeof(Color), "Red"), Category("Meter"), Description("Color of the primary pointer")]
		public Color PointerColor
		{
			get { return pointerColor; }
			set
			{
				pointerColor = value;
				CreateBackground();
			}
		}

		private Color frameColor = Color.Black;

		/// <summary>
		/// Color of the frame of the meter
		/// </summary>
		[Category("Meter")]
		public Color FrameColor
		{
			get { return frameColor; }
			set
			{
				frameColor = value;
				CreateBackground();
			}
		}

		private Padding framePadding = new Padding(5);
		/// <summary>
		/// Size of the frame around the primary part of the meter
		/// </summary>
		[Category("Meter")]
		public Padding FramePadding
		{
			get { return framePadding; }
			set
			{
				framePadding = value;
				CreateBackground();
			}
		}

		private Padding internalPadding = new Padding(5);
		/// <summary>
		/// Internal padding for the meter display
		/// </summary>
		[Category("Meter")]
		public Padding InternalPadding
		{
			get { return internalPadding; }
			set
			{
				internalPadding = value;
				CreateBackground();
			}
		}

		private bool stretch = false;

		/// <summary>
		/// Set to true if the meter should fill the entire control. Set to false to maintain a
		/// rectangular outline.
		/// </summary>
		[DefaultValue(false), Category("Meter"), Description("Set to true if the meter should fill the entire control. Set to false to maintain a rectangular outline.")]
		public bool Stretch
		{
			get { return stretch; }
			set
			{
				stretch = value;
				CreateBackground();
			}
		}

		/// <summary>
		/// Overrides paint event
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);

			if (bgImage != null)
				DrawMeter(e.Graphics);
		}

		/// <summary>
		/// Overrides resize event
		/// </summary>
		/// <param name="e"></param>
		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
			if (this.realGraphics != null)
				this.realGraphics.Dispose();
			this.realGraphics = this.CreateGraphics();
			CreateBackground();
		}

	}
}

3  生成项目,在工具箱中就可以看到该自定义控件了,如下图

把它拉进界面后,如下图:

可以设置它的属性值

Value是设置指针的值

MaxValue是刻度最大值

MinValue是刻度最小值

把MaxValue设置为20时,效果图如下:

好了,本文到此结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值