矩形圆角绘制改进版(附源码)

一、前言

上一篇绘制矩形圆角的方式不够完善,感觉写的太过于复杂,将简单的问题复杂化了,本文对此进行了相应的改进,增强对各个圆角的半径的控制。绘制后的圆角效果图如下:

二、圆角半径设计

对于矩行而言,圆角分为左上角、右上角、左下角和右下角。每一个角都会存在相应的半径,用于控制每一个圆角的绘制。设计如下:

  1     public struct ArcRadius
  2     {
  3         private int _rightBottom;
  4         private int _rightTop;
  5         private int _leftBottom;
  6         private int _leftTop;
  7 
  8         public static readonly ArcRadius Empty =new ArcRadius(0);
  9 
 10         public ArcRadius(int radiusLength)
 11         {
 12             if (radiusLength < 0)
 13             {
 14                 radiusLength = 0;
 15             }
 16 
 17             this._rightBottom = this._rightTop = this._leftBottom = this._leftTop = radiusLength;
 18         }
 19 
 20         public ArcRadius(int leftTop, int rightTop, int leftBottom, int rightBottom)
 21         {
 22             this._rightBottom = rightBottom < 0 ? 0 : rightBottom;
 23             this._rightTop = rightTop < 0 ? 0 : rightTop;
 24             this._leftBottom = leftBottom < 0 ? 0 : leftBottom;
 25             this._leftTop = leftTop < 0 ? 0 : leftTop;
 26         }
 27 
 28         private bool IsAllEqual()
 29         {
 30             return ((this.RightBottom == this.RightTop)
 31                  && (this.RightBottom == this.LeftBottom))
 32                  && (this.RightBottom == this.LeftTop);
 33         }
 34 
 35         public int All
 36         {
 37             get
 38             {
 39                 if (!IsAllEqual())
 40                 {
 41                     return -1;
 42                 }
 43 
 44                 return this.RightBottom;
 45             }
 46             set
 47             {
 48                 if (value < 0)
 49                 {
 50                     value = 0;
 51                 }
 52 
 53                 this.RightBottom = this.RightTop = this.LeftBottom = this.LeftTop = value;
 54             }
 55         }
 56 
 57         public int LeftTop
 58         {
 59             get
 60             {
 61                 return this._leftTop;
 62             }
 63             set
 64             {
 65                 if (value < 0)
 66                 {
 67                     value = 0;
 68                 }
 69 
 70                 this._leftTop = value;
 71             }
 72         }
 73  
 74         public int RightTop
 75         {
 76             get
 77             {
 78                 return this._rightTop;
 79             }
 80             set
 81             {
 82                 if (value < 0)
 83                 {
 84                     value = 0;
 85                 }
 86 
 87                 this._rightTop = value;
 88             }
 89         }
 90        
 91         public int LeftBottom
 92         {
 93             get
 94             {
 95                 return this._leftBottom;
 96             }
 97             set
 98             {
 99                 if (value < 0)
100                 {
101                     value = 0;
102                 }
103 
104                 this._leftBottom = value;
105             }
106         }
107 
108         public int RightBottom
109         {
110             get
111             {
112                 return this._rightBottom;
113             }
114             set
115             {
116                 if (value < 0)
117                 {
118                     value = 0;
119                 }
120 
121                 this._rightBottom = value;
122             }
123         }
124 
125         public static bool operator ==(ArcRadius p1, ArcRadius p2)
126         {
127             return ((((p1.RightTop == p2.RightTop) 
128                 && (p1.RightBottom == p2.RightBottom))
129                 && (p1.LeftBottom == p2.LeftBottom)) 
130                 && (p1.LeftTop == p2.LeftTop));
131         }
132 
133         public static bool operator !=(ArcRadius p1, ArcRadius p2)
134         {
135             return !(p1 == p2);
136         }
137 
138         public override string ToString()
139         {
140             return LeftTop + "" + RightTop + "" + LeftBottom + "" + RightBottom;
141         }
142     }

 

三、GraphicsPathHelper类

主要包括如下两个方法:

public static void DrawRoundRectangle(Graphics g,RoundRectangleArg arg)           用于绘制带有圆角的矩形
public static GraphicsPath CreateRoundPath(Rectangle rect, ArcRadius arcRadius)  用于创建圆角路径,对上文的改进主要在于此方法。不需要对圆角组合进行判断,只需要根据每一个圆角的半径是否大于0而进行相应的圆角绘制。

 

 1     public static class GraphicsPathHelper
 2     {
 3         public static void DrawRoundRectangle(Graphics g,RoundRectangleArg arg)
 4         {
 5             if (g == null || arg.Rectangle.Width == 0 || arg.Rectangle.Height == 0)
 6             {
 7                 return;
 8             }
 9 
10             using (SmoothingModeGraphics smoothingMode = new SmoothingModeGraphics(g, SmoothingMode.AntiAlias))
11             {
12                 using (var path = CreateRoundPath(arg.Rectangle, arg.ArcRadius))
13                 {
14                     if (arg.DrawBackground)
15                     {
16                         using (var fillBrush = new LinearGradientBrush(
17                             arg.Rectangle, arg.StartColor, arg.EndColor, arg.LinearGradientMode))
18                         {
19                             var blend = new ColorBlend(2);
20                             blend.Positions[0] = 0.0f;
21                             blend.Positions[1] = 1.0f;
22                             blend.Colors[0] = arg.StartColor;
23                             blend.Colors[1] = arg.EndColor;
24                             fillBrush.InterpolationColors = blend;
25                             g.FillPath(fillBrush, path);
26                         }
27                     }
28 
29                     if (arg.DrawBorder)
30                     {
31                         using (var pen = new Pen(new SolidBrush(arg.BorderColor), arg.BorderWidth))
32                             g.DrawPath(pen, path);
33                     }
34 
35                     if (arg.DrawInnerBorder)
36                     {
37                         Rectangle rectangle = arg.Rectangle;
38                         rectangle.Inflate(-2, -2);
39                         var innerPath = CreateRoundPath(rectangle, arg.ArcRadius);
40 
41                         using (var pen = new Pen(new SolidBrush(arg.InnerBorderColor), arg.InnerBorderWidth))
42                         {
43                             g.DrawPath(pen, innerPath);
44                         }
45                     }
46                 }
47             }
48         }
49 
50         public static GraphicsPath CreateRoundPath(Rectangle rect, ArcRadius arcRadius)
51         {
52             var path = new GraphicsPath();
53 
54             if (rect.Width == 0 || rect.Height == 0)
55             {
56                 return path;
57             }
58 
59             if (arcRadius.LeftTop > 0)
60             {
61                 path.AddArc(
62                     rect.Left, rect.Top, arcRadius.LeftTop, arcRadius.LeftTop, 18090);
63             }
64 
65             path.AddLine(new Point(rect.Left + arcRadius.LeftTop, rect.Top),
66                          new Point(rect.Right - arcRadius.RightTop, rect.Top));
67 
68             if (arcRadius.RightTop > 0)
69             {
70                 path.AddArc(rect.Right - arcRadius.RightTop, rect.Top,
71                     arcRadius.RightTop, arcRadius.RightTop, -9090);
72             }
73 
74             path.AddLine(new Point(rect.Right, rect.Top + arcRadius.RightTop),
75                          new Point(rect.Right, rect.Bottom - arcRadius.RightBottom));
76 
77             if (arcRadius.RightBottom > 0)
78             {
79                 path.AddArc(rect.Right - arcRadius.RightBottom, rect.Bottom - arcRadius.RightBottom,
80                     arcRadius.RightBottom, arcRadius.RightBottom, 090);
81             }
82 
83             path.AddLine(new Point(rect.Right - arcRadius.RightBottom, rect.Bottom),
84                          new Point(rect.Left + arcRadius.LeftBottom, rect.Bottom));
85 
86             if (arcRadius.LeftBottom > 0)
87             {
88                 path.AddArc(rect.Left, rect.Bottom - arcRadius.LeftBottom,
89                     arcRadius.LeftBottom, arcRadius.LeftBottom, 9090);
90             }
91 
92             path.AddLine(new Point(rect.Left, rect.Bottom - arcRadius.LeftBottom),
93                          new Point(rect.Left, rect.Top + arcRadius.LeftTop));
94 
95             path.CloseFigure();
96 
97             return path;
98         }
99     }

 

、应用

 应用的话比较简单,只需要设置RoundRectangleArg参数,然后调用GraphicsPathHelper.DrawRoundRectangle即可。

 RoundRectangleArg arg = new RoundRectangleArg();
 arg.Rectangle = rectangle;
 arg.ArcRadius = new ArcRadius((int)this.numericLeftBottomRadiuds.Value, (int)this.numericRightTopRadiuds.Value,
                         (int)this.numericLeftTopRadiuds.Value, (int)this.numericRightBottomRadiuds.Value);
 arg.BorderColor = Color.FromName((this.cboBorderColors.SelectedItem ?? string.Empty).ToString());
 arg.InnerBorderColor = Color.FromName((this.cboInnerBorderColors.SelectedItem ?? string.Empty).ToString());
 arg.StartColor = Color.FromName((this.cboStartColors.SelectedItem ?? string.Empty).ToString());

 arg.EndColor = Color.FromName((this.cboEndColors.SelectedItem ?? string.Empty).ToString());
 arg.LinearGradientMode = gradientMode;
 arg.DrawInnerBorder = this.ckbDrawInnerBorder.Checked;
 arg.DrawBorder = this.ckbDrawBorder.Checked;
 arg.DrawBackground = this.ckbDrawBg.Checked;
 arg.BorderWidth = (int)this.numericBorderWidth.Value;
 arg.InnerBorderWidth = (int)this.numericInnerBorderWidth.Value;

               

 GraphicsPathHelper.DrawRoundRectangle(graphic, arg);

 

五、总结

 前一篇的随笔主要是应用位操作来处理枚举,将问题复杂化了。本文进行了相应的改进,代码相对来说更加清晰与简洁。 改进版的源码下载如下:

 

 源码下载:矩形圆角绘制改进版

posted @ 2012-09-22 15:16  jasen.kin  阅读(5768)  评论(13编辑  收藏  举报