zoukankan      html  css  js  c++  java
  • 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         }
  • 相关阅读:
    java.lang.OutOfMemoryError: GC overhead limit exceeded
    Ural 1146 Maximum Sum(DP)
    [算法系列之四]优先级队列
    Python源代码--整数对象(PyIntObject)的内存池
    3星|何帆《猜测与偏见》:社科书评集
    4星|《认识经济》:全面系统的经济学普及读物,鸿篇巨制,价格超贵
    3星|《东方启动点》:民营企业家们的故事,故事多分析概括少
    2星|《大师的管理课》:畅销书作家们的35篇励志散文
    3.5星|《蓝海战略2》:实施蓝海战略的具体工具与方法。案例牵强且偏老旧
    2星|《读懂华为30年》:基于公开资料的整理和肤浅的发挥
  • 原文地址:https://www.cnblogs.com/twzy/p/4922976.html
Copyright © 2011-2022 走看看