上一篇绘制矩形圆角的方式不够完善,感觉写的太过于复杂,将简单的问题复杂化了,本文对此进行了相应的改进,增强对各个圆角的半径的控制。绘制后的圆角效果图如下:
二、圆角半径设计
对于矩行而言,圆角分为左上角、右上角、左下角和右下角。每一个角都会存在相应的半径,用于控制每一个圆角的绘制。设计如下:
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而进行相应的圆角绘制。
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, 180, 90);
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, -90, 90);
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, 0, 90);
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, 90, 90);
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);
五、总结
前一篇的随笔主要是应用位操作来处理枚举,将问题复杂化了。本文进行了相应的改进,代码相对来说更加清晰与简洁。 改进版的源码下载如下:
源码下载:矩形圆角绘制改进版