一、前言
本文主要介紹C# GDI+如何繪制矩行的圓角,其中涉及到如何使用位操作來處理組合的技巧。GDI+的本質在於,它能夠替代開發人員實現與顯示器及其它外部設備的交互。對於控件美化而言,需要達到自己期望的效果,GDI+必不可少。繪制後的圓角效果圖如下:
二、圓角枚舉與相應組合處理設計
對於矩行而言,圓角分為左上角、右上角、左下角和右下角。組合情況就分為無圓角、一個圓角、二個圓角、三個圓角以及四個圓角。枚舉需要滿足該組合情況,沒必要在枚舉中將 全部組合列出,只需要通過位操作就能計算出屬於哪種組合。枚舉類設計如下:
[Flags] public enum RoundStyle { None = 0, TopLeft = 1, TopRight = 2, BottomLeft = 4, BottomRight = 8 , All = TopLeft | TopRight | BottomLeft | BottomRight }
矩行的圓角所有組合情況如下:
RoundStyle.None
RoundStyle.All
RoundStyle.BottomLeft
RoundStyle.BottomRight
RoundStyle.TopLeft
RoundStyle.TopRightRoundStyle.BottomRight | RoundStyle.BottomLeft
RoundStyle.BottomRight | RoundStyle.TopRight
RoundStyle.TopRight | RoundStyle.TopLeft
RoundStyle.BottomLeft | RoundStyle.TopLeft
RoundStyle.BottomRight | RoundStyle.TopLeft
RoundStyle.TopRight | RoundStyle.BottomLeftRoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopLeft
RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopRight
RoundStyle.BottomLeft | RoundStyle.TopLeft | RoundStyle.TopRight
RoundStyle.BottomRight | RoundStyle.TopRight | RoundStyle.TopLeft
對於每一種組合,必須提供相應的操作來執行路徑計算,這主要是因為GraphicsPath的路徑是有順序的。因此所有組合對應的處理方式如下:
private static IDictionary<RoundStyle, Action<GraphicsPath, Rectangle, int, int>> CreateRoundStylesEventContainer() { var container = new Dictionary<RoundStyle, Action<GraphicsPath, Rectangle, int, int>>(); container.Add(RoundStyle.None, (path, rect, radius, radiusAdjustment) => { path.AddRectangle(rect); }); container.Add(RoundStyle.All, AddAllRoundStyle); container.Add(RoundStyle.BottomLeft, AddBottomLeftRoundStyle); container.Add(RoundStyle.BottomRight, AddBottomRightRoundStyle); container.Add(RoundStyle.TopLeft, AddTopLeftRoundStyle); container.Add(RoundStyle.TopRight, AddTopRightRoundStyle); container.Add(RoundStyle.BottomRight | RoundStyle.BottomLeft, AddBottomRightAndBottomLeftRoundStyle); container.Add(RoundStyle.BottomRight | RoundStyle.TopRight, AddBottomRightAndTopRightRoundStyle); container.Add(RoundStyle.TopRight | RoundStyle.TopLeft, AddTopRightAndTopLeftRoundStyle); container.Add(RoundStyle.BottomLeft | RoundStyle.TopLeft, AddBottomLeftAndTopLeftRoundStyle); container.Add(RoundStyle.BottomRight | RoundStyle.TopLeft, AddBottomRightAndTopLeftRoundStyle); container.Add(RoundStyle.TopRight | RoundStyle.BottomLeft, AddTopRightAndBottomLeftRoundStyle); container.Add(RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopLeft, AddBottomAndTopLeftRoundStyle); container.Add(RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopRight, AddBottomAndTopRightRoundStyle); container.Add(RoundStyle.BottomLeft | RoundStyle.TopLeft | RoundStyle.TopRight, AddTopAndBottomLeftRoundStyle); container.Add(RoundStyle.BottomRight | RoundStyle.TopRight | RoundStyle.TopLeft, AddTopAndBottomRightRoundStyle); return container; }
三、GraphicsPath.AddArc方法
GraphicsPath.AddArc 方法如下:
public void AddArc(Rectangle rect, float startAngle, float sweepAngle); public void AddArc(RectangleF rect, float startAngle, float sweepAngle); public void AddArc(float x, float y, float width, float height, float startAngle, float sweepAngle); public void AddArc(int x, int y, int width, int height, float startAngle, float sweepAngle);
此方法主要是繪制圓角的,繪制的方式與二位坐標的角度是不一樣,官方參數資料如下:
x 矩形區域左上角的 X 軸坐標,這個矩形區域定義用來繪制弧形的橢圓形。
y 矩形區域左上角的 Y 軸座標,這個矩形區域定義用來繪制弧形的橢圓形。
width 矩形區域的寬度,這個矩形區域定義用來繪制弧形的橢圓形。
height 矩形區域的高度,這個矩形區域定義用來繪制弧形的橢圓形。
startAngle 弧形的開始點角度,順時針自 X 軸所測得的度數。
sweepAngle 介於弧形的 startAngle 和結束點的角度。
如果圓形中具有先前的直線或曲線,會加入線段來將先前線段的結束點連接到弧形的開端。
弧形是沿著指定矩形范圍內的橢圓形周圍所描繪的。弧形的開始點是由橢圓形的 X 軸 (0 度角) 順時針測量開始點角度的度數所決定。結束點位置的決定很類似,從開始點順時針測量跨越角度的度數所決定。如果跨越的角度大於 360 度或小於 -360 度,則弧形分別跨越了 360 度或 -360 度。
弧形的開始點是由橢圓形的 X 軸 (0 度角) 順時針測量開始點角度的度數所決定,GraphicsPath增加對象的順序也是需要注意的(有部分連接線是系統繪制的)。此處與數學中二位坐標定義的角度是反方向的,需要特別注意。
四、繪制圓角組合
3.1 繪制一個圓角
矩行的一個圓角所有組合情況如下:RoundStyle.BottomLeft、RoundStyle.BottomRight、RoundStyle.TopLeft、RoundStyle.TopRight。繪制方法如下:
繪制一個圓角 private static void AddBottomLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomLeftArc(rect, radius, path, radiusAdjustment); AddTopLine(rect, path, radiusAdjustment); AddRightLine(rect, path, radiusAdjustment); } private static void AddBottomRightRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomRightArc(rect, radius, path, radiusAdjustment); AddLeftLine(rect, path, radiusAdjustment); AddTopLine(rect, path, radiusAdjustment); } private static void AddTopRightRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomLine(rect, path, radiusAdjustment); AddLeftLine(rect, path, radiusAdjustment); } private static void AddTopLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopLeftArc(rect, radius, path, radiusAdjustment); AddRightLine(rect, path, radiusAdjustment); AddBottomLine(rect, path, radiusAdjustment); }
效果圖如下:
3.2 繪制二個圓角
矩行的一個圓角所有組合情況如下:
RoundStyle.BottomRight | RoundStyle.BottomLeft
RoundStyle.BottomRight | RoundStyle.TopRight
RoundStyle.TopRight | RoundStyle.TopLeft
RoundStyle.BottomLeft | RoundStyle.TopLeft
RoundStyle.BottomRight | RoundStyle.TopLeft
RoundStyle.TopRight | RoundStyle.BottomLeft。
繪制方法如下:
繪制二個圓角 private static void AddTopRightAndBottomLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomLineWithLeftOffset(path, rect, radius, radiusAdjustment, false); AddBottomLeftArc(rect, radius, path, radiusAdjustment); AddTopLineWithRightOffset(path, rect, radius, radiusAdjustment); } private static void AddBottomRightAndTopLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomRightArc(rect, radius, path, radiusAdjustment); AddBottomLineWithRightOffset(path, rect, radius, radiusAdjustment); AddTopLeftArc(rect, radius, path, radiusAdjustment); AddTopLineWithLeftOffset(path, rect, radius, radiusAdjustment); } private static void AddBottomLeftAndTopLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomLeftArc(rect, radius, path, radiusAdjustment); AddTopLeftArc(rect, radius, path, radiusAdjustment); AddRightLine(rect, path, radiusAdjustment); } private static void AddTopRightAndTopLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopLeftArc(rect, radius, path, radiusAdjustment); AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomLine(rect, path, radiusAdjustment); } private static void AddBottomRightAndTopRightRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomRightArc(rect, radius, path, radiusAdjustment); AddLeftLine(rect, path, radiusAdjustment); } private static void AddBottomRightAndBottomLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomRightArc(rect, radius, path, radiusAdjustment); AddBottomLeftArc(rect, radius, path, radiusAdjustment); AddTopLine(rect, path, radiusAdjustment); }
效果圖如下:
3.2 繪制三個圓角
矩行的一個圓角所有組合情況如下:
RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopLeft
RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopRight
RoundStyle.BottomLeft | RoundStyle.TopLeft | RoundStyle.TopRight
RoundStyle.BottomRight | RoundStyle.TopRight | RoundStyle.TopLeft。
繪制方法如下:
繪制三個圓角 private static void AddTopAndBottomRightRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopLeftArc(rect, radius, path, radiusAdjustment); AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomRightArc(rect, radius, path, radiusAdjustment); AddBottomLineWithRightOffset(path, rect, radius, radiusAdjustment); } private static void AddTopAndBottomLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopLeftArc(rect, radius, path, radiusAdjustment); AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomLineWithLeftOffset(path, rect, radius, radiusAdjustment, false); AddBottomLeftArc(rect, radius, path, radiusAdjustment); } private static void AddBottomAndTopRightRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomRightArc(rect, radius, path, radiusAdjustment); AddBottomLeftArc(rect, radius, path, radiusAdjustment); AddTopLineWithRightOffset(path, rect, radius, radiusAdjustment); AddTopRightArc(rect, radius, path, radiusAdjustment); } private static void AddBottomAndTopLeftRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddBottomRightArc(rect, radius, path, radiusAdjustment); AddBottomLeftArc(rect, radius, path, radiusAdjustment); AddTopLeftArc(rect, radius, path, radiusAdjustment); AddTopLineWithLeftOffset(path, rect, radius, radiusAdjustment); }
效果圖如下:
3.4 繪制四個圓角
矩行的四個圓角所有組合情況如下:RoundStyle.All或者RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopLeft | RoundStyle.TopRight。
繪制方法如下:
繪制四個圓角 private static void AddAllRoundStyle(GraphicsPath path, Rectangle rect, int radius, int radiusAdjustment) { AddTopLeftArc(rect, radius, path, radiusAdjustment); AddTopRightArc(rect, radius, path, radiusAdjustment); AddBottomRightArc(rect, radius, path, radiusAdjustment); AddBottomLeftArc(rect, radius, path, radiusAdjustment); }
效果圖如下:
四、總結
繪制圓角在美化控件方面的場景還是比較多的,本文采用枚舉的位操作來對所有情況進行操作。有一段時間沒寫隨筆了,可以寫的東西很多,由於個人的時間問題卻一直拖到現在。上面的圓角繪制例子是昨天作為練習寫的,只是簡單的手動測試了一下,如有BUG請及時通知本人,不勝感激。目前開發的產品很多控件都需要自繪,統計學需要寫的算法也比較多。雖然項目成員總人數為100,但開發所占的比例才40%不到,任重而道遠。
源碼下載: 矩陣圓角繪制源碼
http://files.cnblogs.com/jasenkin/Winform/Jasen.Framework.rar
作者:JasenKin
出處:http://www.cnblogs.com/jasenkin/