C# 制作 仪表

以前在百度写的文档,转移到此处

前些天在做NetAnalyzer时,需要使用一个指针仪表,网上看了一下,也有人做过,但是大部分都是收费的,本着自力更生的原则,于是决定自己设计一个,今天拿出来有读者分享一下。

首先是截图:

该仪表是以控件形式提供

在开始之前还要赘述一点关于GDI+中角度的计算

如下图

在WinForm中左上角的点位(0,0),即原点,而其起始角则是图中划线处开始的,即为 rad=0;

在绘图时,尤其是做过扇形统计图的人应该比较清楚。

--------------------------------------------------------

接下来就是正式开始

首先新建控件,设置为witdth=height=150 ,可以自己定义,我在这里时可以自适应的

将背景颜色设置为Transparent(透明色),方便以后使用时减少干扰

在该仪表中主要分为两部分:背景部分(外框,刻度,单位等一些列基本不需要频繁变化的部分),前景部分(指针部分)

所以为了不是两个图层不相互影响,我们将背景绘制在控件的BackgroundImage 属性上,而指针部分则需要一个pictrueBox控件作为载体。

首先画背景

在绘制背景时,又分为外框、刻度,指针固定中心等

  1   // 绘制背景 用来总体控制背景的绘制
  2         private void DrawBackImg()
  3         {
  4             Bitmap bit = new Bitmap(this.Width, this.Height);
  5             Graphics gp = Graphics.FromImage(bit);
  6             gp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  7             #region 在这里可以扩展需要绘制的背景项目
  8             //外框
  9             drawFrame(gp);
 10             // 画刻度
 11             DrawRuling(gp);
 12             //画点
 13             drawPoint(gp);
 14
 15             //绘制单位
 16
 17             DrawUnitStr(gp);
 18
 19             #endregion
 20
 21            //当绘制完成后,直接直接设置为背景
 22
 23             this.BackgroundImage = bit;
 24         }
 25
 26
 27       //绘制单位
 28
 29        private void DrawUnitStr(Graphics gp)
 30         {
 31             int cer = _diameter / 2;
 32             gp.DrawString(_unitStr, new Font("宋体", 10), new SolidBrush(_frameColor), new PointF(cer, (float)(cer - cer * 0.3)), strFormat);
 33
 34         }
 35
 36         /// <summary>
 37         /// 画外框
 38         /// </summary>
 39         /// <param name="gp"></param>
 40         private void drawFrame(Graphics gp)
 41         {
 42             Pen pen = new Pen(_frameColor, 2);
 43             Rectangle rec = new Rectangle(5, 5, _diameter - 10, _diameter - 10);
 44             gp.DrawEllipse(pen, rec);
 45         }
 46         // 画刻度  此次较为复杂,主要是在绘制刻度值时需要处理
 47         private void DrawRuling(Graphics gp)
 48         {
 49             //刻度
 50             int cerX = _diameter / 2;
 51             int cerY = _diameter / 2;
 52
 53            //这里需要注意,因外在上面的图中标识了rad=0的位置,而我们的仪表时270度的,0点在135度处,
 54
 55            //为了符合该效果所以起始位置设为135度。
 56             float start = 135;
 57             float sweepShot = 0;
 58             int dx = 0;
 59             int dy = 0;
 60             int soildLenght = 8;
 61             Pen linePen = new Pen(_frameColor, 1);
 62             float span = (float)(_maxValue / 30);
 63             float sp = 0;
 64             //用于右边数字右对齐
 65             StringFormat stf = new StringFormat();
 66             stf.Alignment = StringAlignment.Far;
 67
 68             StringFormat stfMid = new StringFormat();
 69             stfMid.Alignment = StringAlignment.Center;
 70             stfMid.LineAlignment = StringAlignment.Center;
 71             for (int i = 0; i <= 30; i++)
 72             {
 73                 //注意此处,C#提供的三角函数计算中使用的弧度值,而此处获取的是角度值,需要转化
 74
 75                 double rad = (sweepShot + start) * Math.PI / 180;
 76                 float radius = _diameter / 2 - 5;
 77                 int px = (int)(cerX + radius * Math.Cos(rad));
 78                 int py = (int)(cerY + radius * Math.Sin(rad));
 79                 if (sweepShot % 15 == 0)
 80                 {
 81                     linePen.Width = 2;
 82
 83                    //计算刻度中的粗线
 84                     dx = (int)(cerX + (radius - soildLenght) * Math.Cos(rad));
 85                     dy = (int)(cerY + (radius - soildLenght) * Math.Sin(rad));
 86
 87                     //绘制刻度值,注意字串对其方式
 88                     string str = sp.ToString("f0");
 89                     if (sweepShot <= 45)
 90                     {
 91                         gp.DrawString(str, new Font("宋体", 9), new SolidBrush(_frameColor), new PointF(dx, dy - 5));
 92                     }
 93                     else if (sweepShot > 45 && sweepShot < 135)
 94                     {
 95                         gp.DrawString(str, new Font("宋体", 9), new SolidBrush(_frameColor), new PointF(dx, dy));
 96                     }
 97                     else if (sweepShot == 135)
 98                     {
 99                         gp.DrawString(str, new Font("宋体", 9), new SolidBrush(_frameColor), new PointF(dx, dy + 10), stfMid);
100                     }
101                     else if (sweepShot > 135 && sweepShot < 225)
102                     {
103                         gp.DrawString(str, new Font("宋体", 9), new SolidBrush(_frameColor), new PointF(dx, dy), stf);
104                     }
105                     else if (sweepShot >= 225)
106                     {
107                         gp.DrawString(str, new Font("宋体", 9), new SolidBrush(_frameColor), new PointF(dx, dy - 5), stf);
108                     }
109
110                 }
111                 else
112                 {
113
114                     //计算刻度中细线
115
116                     linePen.Width = 1;
117                     dx = (int)(cerX + (radius - soildLenght + 2) * Math.Cos(rad));
118                     dy = (int)(cerY + (radius - soildLenght + 2) * Math.Sin(rad));
119                 }
120
121                  //绘制刻度线
122                 gp.DrawLine(linePen, new Point(px, py), new Point(dx, dy));
123                 sp += span;
124                 sweepShot += 9;
125             }
126         }
127         //画中间的点
128         private void drawPoint(Graphics gp)
129         {
130             Pen p = new Pen(_frameColor);
131             int tmpWidth = 6;
132             int px = _diameter / 2 - tmpWidth;
133
134             gp.DrawEllipse(p, new Rectangle(px, px, 2 * tmpWidth, 2 * tmpWidth));
135
136             //在画点时,我使用了指针的颜色,这样看起来,更真实一点
137             gp.FillEllipse(new SolidBrush(_pinColor), new Rectangle(px + 2, px + 2, 2 * tmpWidth - 4, 2 * tmpWidth - 4));
138         }
139
140 -------------------------------------------
141
142 画指针
143
144 绘制指正时,最大的问题就是界面闪速,除了在控件构造方法里添加如下代码:
145
146         SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
147         UpdateStyles();
148
149 绘制方式也需要调整,方法如下:
150
151
152
153   //为了方式绘制指针时产生的闪烁,PictureBox添加该事件方法
154
155         private void pic_Paint(object sender, PaintEventArgs e)
156         {
157               DrawForeImg(e.Graphics);
158        }
159
160       //使用方法
161
162          public double ChangeValue
163         {
164             get { return _changeValue; }
165             set
166             {
167                 if (value <= _maxValue)
168                     _changeValue = value;
169                 else
170                 {
171                     //完成自适应性
172                     MaxValue = value;
173                     _changeValue = value;
174                 }
175                //通过该方法,可以使指针自动绘制(其实就是强制重绘)
176
177                pic.Invalidate();
178             }
179         }
180
181         //指针的具体画法
182
183         private void DrawForeImg(Graphics gp)
184         {
185             Bitmap bit = new Bitmap(this.Width, this.Height);
186             Graphics g = Graphics.FromImage(bit);
187             g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
188
189             //画针
190             DrawPin(g);
191             DrawString(g);
192
193             //注意此处的绘制方式,这样可以有效减少界面的闪烁问题。
194             gp.DrawImage(bit, new Point(0, 0));
195             g.Dispose();
196
197         }
198         //画针
199         private void DrawPin(Graphics g)
200         {
201             int cer = _diameter / 2;
202             float start = 135;
203             float sweepShot = (float)(_changeValue / _maxValue * 270);
204
205             Pen linePen = new Pen(_pinColor, 1);
206             Pen NxPen = new Pen(_pinColor, 2);
207             Pen xPen = new Pen(_pinColor, 5);
208             double rad = (sweepShot + start) * Math.PI / 180;
209             float radius = _diameter / 2 - 5;
210             int dx = (int)(cer + (_PinLen) * Math.Cos(rad));
211             int dy = (int)(cer + (_PinLen) * Math.Sin(rad));
212
213             int px = (int)(cer + (_PinLen * 0.4) * Math.Cos(rad));
214             int py = (int)(cer + (_PinLen * 0.4) * Math.Sin(rad));
215
216             int nx = (int)(cer - (NxPinLen) * Math.Sin(rad));
217             int ny = (int)(cer - (NxPinLen) * Math.Cos(rad));
218             g.DrawLine(linePen, new Point(cer, cer), new Point(dx, dy));
219             g.DrawLine(NxPen, new Point(cer, cer), new Point(px, py));
220             g.DrawLine(xPen, new Point(cer, cer), new Point(ny, nx));
221         }
222
223        //绘制在仪表下面的值
224
225         private void DrawString(Graphics g)
226         {
227             int cer = _diameter / 2;
228             string str = _changeValue.ToString("F2");
229             g.DrawString(str, new Font("宋体", 9), new SolidBrush(_pinColor), new PointF(cer, (float)(cer + cer * 0.4)), strFormat);
230         }
时间: 2024-07-31 01:52:51

C# 制作 仪表的相关文章

Swift - 制作一个录音机(声音的录制与播放)

1,技术介绍 (1)AVFoundation.framework框架提供了AVAudioRecorder类.它可以实现录音功能. (2)而使用该框架的AVAudioPlayer类,可以实现声音的播放. 2,下面制作一个录音机样例 (1)按住录音按钮则开始录音,松开则停止录音.录音文件保存在用户文件夹下. (2)录音过程中会实时显示声音的音量大小(这个可以用来做声音脉冲图,获得更好的展示效果) (3)点击播放录音则可播放录制的声音文件. 3,效果图如下: 4,代码如下: 1 2 3 4 5 6 7

Essential Gauge for WPF仪表控件下载及介绍

Essential Gauge for WPF是一款强大的仪表控件,为你的商业应用程序加入令人震撼的仪表,控件提供了Circular Gauge.Digital Gauge和Linear Gauge仪表类型,多种可视的仪表样式. 具体功能: Circular Gauge 支持圆形.半圆形和自定义仪表框架支持在单个仪表里使用多个比例刻度和指针支持对数比例标签格式化支持公式支持range和状态指示器 Linear Gauge 完全的自定义仪表元素:状态指示器.指针.刻度.指针位置.标签位置.刻度位置

工业串口触摸屏开发制作mp3播放器,单片机或PLC通过串口控制播放MP3音频方法

在工业控制系统中将音乐或语音MP3的美和工控结合在一起,给人以赏心悦目的感受.随着工业控制的发展,对工业控制的控制要求也越来越高,使得越来越多的控制部分不是指简单的现场控制,还需要增加音乐播放或语音提示,使得控制系统更加人性化. 这里介绍广州易显的工业串口触摸屏或者ARM工控机连接单片机或者PLC,使用工业串口触摸屏开发制作mp3的方法.跟电脑的播放器一样,具有播放,暂停,停止,控制播放进度,上一首,下一首等功能.可以在人机界面上控制播放MP3音乐或者语音提示.也可以使用单片机或PLC控制播放的

如何制作商务礼仪PPT模板?

商务礼仪是在商务活动中的行为准则,商务礼仪具体可以表述为三方面:一可以提供个人的素质:二有助于建立良好的人际沟通关系:三既能维护个人形象也能维护企业形象.看来商务礼仪在职场中是一个很重要的存在了.那么商务礼仪PT模板要怎么制作呢?看看小编的制作思路吧.可以从三个人方向来指定:一. 商务礼仪的作用:1. 内强素质,外塑形象2. 有助于对交往对象的恰倒好处的表示尊重和友善3. 维护形象(维护个人.企业以及国家的形象)二.商务礼仪的原则:1. 接受对方:必须注意交谈时的三不准:不要打断别人;不要轻易补

怎么制作室内720全景?

水平720度全能观看的场景图片,720度全景从专业的角度来讲就是视角逾越人的正常视角的图像.可以看到天和地的图片.那么,720度VR室内全景效果图怎么做呢? 室内全景如何拍摄 越来越多的行业在应用着360全景展示.所以,随着科技的发展.现在有很多的企业在网站中添加网展公司制作的360全景展示.小编原来讲过如何在室外拍摄全景,今天就教下大家如何在室内拍摄出好看的全景照片: 一.光线 想其艺术性要求不高,如何利用有限的光线是室内拍摄最具挑战性的难点.由于室内光源是固定的补光除外)也是不可撑控的唯一能

制作SD(8G)卡Linux镜像,使得ZC706开发板可以从SD卡启动进入Linux系统

转自网络,供学习记录使用,红色部分是我实验时,这篇文章和网站稍有出入的地方. 目的:制作SD(8G)卡Linux镜像,使得ZC706开发板可以从SD卡启动进入Linux系统 在http://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz/quickstart/zynq(姑且把这个链接成为链接1吧)链接中找到 图1 点击绿色字体的链接,下载镜像原始文件.这里有不同时期的版本,本说明中选择 图2 下载的原始文件为:2014_R2-

DEDE5.7如何制作网站地图?

DEDE用的人很多,可能大家在使用的过程中会碰到一些问 题,这很正常的,今天我们来讲讲DEDE5.7如何制作网站地图,其实网站地图分两种,一种做给网友看的,方便网友可以方便地找到自己想浏览的内容,另外 一种是做给搜索引擎蜘蛛看,方便蜘蛛在你网站上面抓取内容.    当然,我们这里讲的主要是针对蜘蛛的,因为DEDE默认的就有针对用户的网站地图,主要是以栏目的形式展现,这个可以在DEDE后台自行生成.其实大家印象当中的网站地图是XML格式的,一般命名成sitemap.xml,接下来进入正题.    

360全景照片怎么制作哪个平台好?

360全景照片如何制作平台哪家好?全景图在广告宣传等方面应用非常广泛,用广角的手法来渲染衬托,其实很多全景图都是由多张图片拼接而成,展示功能方面还是非常完善的,在行业展示方面酷雷曼3DVR智能全景展示系统受到了众多商家的追捧! 酷雷曼3DVR智能全景系统 酷雷曼全景云平台支持多种设备播放全景,以及随时随地浏览高清全景.特色漫游,一键分享至微信朋友圈及多个社交平台指定好友,轻松传递全景世界无限精彩.http://www.kuleiman.com/kuleiman/100689/ 360全景顾名思义

怎么制作全景主题?

怎么制作全景主题?如何将普通图片转换成3D立体图片呢?由于3D图片是利用红蓝双色分离原理所产生的错觉而形成的立体效果.据此我们可以利用PS来制作3D立体图片效果.以下就是具体的制作方法. 方法/步骤 利用PS打开原图,此时效果如图:    在"图层"面板中,双击"背景层",将其转换成"图层0". 将"图层0"拖动到"创建新图层"按钮上以创建"图层0副本"层.    双击"图层0