• C# GDI+绘制矩形圆角


    一、前言

    本文主要介绍C# GDI+如何绘制矩行的圆角,其中涉及到如何使用位操作来处理组合的技巧。GDI+的本质在于,它能够替代开发人员实现与显示器及其它外部设备的交互。对于控件美化而言,需要达到自己期望的效果,GDI+必不可少。绘制后的圆角效果图如下:

    二、圆角枚举与相应组合处理设计

     对于矩行而言,圆角分为左上角、右上角、左下角和右下角。组合情况就分为无圆角、一个圆角、二个圆角、三个圆角以及四个圆角。枚举需要满足该组合情况,没必要在枚举中将 全部组合列出,只需要通过位操作就能计算出属于哪种组合。枚举类设计如下:

     1    [Flags]
     2     public enum RoundStyle
     3     {     
     4         None = 0,     
     5         TopLeft = 1,
     6         TopRight = 2,
     7         BottomLeft = 4,
     8         BottomRight = 8 ,
     9         All = TopLeft | TopRight | BottomLeft | BottomRight
    10     }
    矩行的圆角所有组合情况如下:
    RoundStyle.None   
    RoundStyle.All       
    RoundStyle.BottomLeft
    RoundStyle.BottomRight
    RoundStyle.TopLeft

    RoundStyle.TopRight

    RoundStyle.BottomRight | RoundStyle.BottomLeft
    RoundStyle.BottomRight | RoundStyle.TopRight
    RoundStyle.TopRight | RoundStyle.TopLeft
    RoundStyle.BottomLeft | RoundStyle.TopLeft
    RoundStyle.BottomRight | RoundStyle.TopLeft
    RoundStyle.TopRight | RoundStyle.BottomLeft

    RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopLeft
    RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopRight
    RoundStyle.BottomLeft | RoundStyle.TopLeft | RoundStyle.TopRight
    RoundStyle.BottomRight | RoundStyle.TopRight | RoundStyle.TopLeft

    对于每一种组合,必须提供相应的操作来执行路径计算,这主要是因为GraphicsPath的路径是有顺序的。因此所有组合对应的处理方式如下:

     1         private static IDictionary<RoundStyle, Action<GraphicsPath, Rectangle, intint>>
     2             CreateRoundStylesEventContainer()
     3         {
     4             var container = new Dictionary<RoundStyle, Action<GraphicsPath, Rectangle, intint>>();
     5 
     6             container.Add(RoundStyle.None, (path, rect, radius, radiusAdjustment) => { path.AddRectangle(rect); });
     7             container.Add(RoundStyle.All, AddAllRoundStyle);
     8 
     9             container.Add(RoundStyle.BottomLeft, AddBottomLeftRoundStyle);
    10             container.Add(RoundStyle.BottomRight, AddBottomRightRoundStyle);
    11             container.Add(RoundStyle.TopLeft, AddTopLeftRoundStyle);
    12             container.Add(RoundStyle.TopRight, AddTopRightRoundStyle);
    13 
    14             container.Add(RoundStyle.BottomRight | RoundStyle.BottomLeft, AddBottomRightAndBottomLeftRoundStyle);
    15             container.Add(RoundStyle.BottomRight | RoundStyle.TopRight, AddBottomRightAndTopRightRoundStyle);
    16             container.Add(RoundStyle.TopRight | RoundStyle.TopLeft, AddTopRightAndTopLeftRoundStyle);
    17             container.Add(RoundStyle.BottomLeft | RoundStyle.TopLeft, AddBottomLeftAndTopLeftRoundStyle);
    18             container.Add(RoundStyle.BottomRight | RoundStyle.TopLeft, AddBottomRightAndTopLeftRoundStyle);
    19             container.Add(RoundStyle.TopRight | RoundStyle.BottomLeft, AddTopRightAndBottomLeftRoundStyle);
    20 
    21             container.Add(RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopLeft, AddBottomAndTopLeftRoundStyle);
    22             container.Add(RoundStyle.BottomLeft | RoundStyle.BottomRight | RoundStyle.TopRight, AddBottomAndTopRightRoundStyle);
    23             container.Add(RoundStyle.BottomLeft | RoundStyle.TopLeft | RoundStyle.TopRight, AddTopAndBottomLeftRoundStyle);
    24             container.Add(RoundStyle.BottomRight | RoundStyle.TopRight | RoundStyle.TopLeft, AddTopAndBottomRightRoundStyle);
    25 
    26             return container;
    27         }

    三、GraphicsPath.AddArc方法

    GraphicsPath.AddArc 方法如下:

    1 public void AddArc(Rectangle rect, float startAngle, float sweepAngle);
    2 public void AddArc(RectangleF rect, float startAngle, float sweepAngle);
    3 public void AddArc(float x, float y, float width, float height, float startAngle, float sweepAngle);
    4 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%不到,任重而道远。

    源码下载: 矩阵圆角绘制源码

  • 相关阅读:
    Mysql 多字段去重
    一个不错的PHP二维数组排序函数简单易用存用
    关于威富通的微信扫码支付处理思路和流程
    牛顿迭代法求解平方根
    impex 语法
    屏幕取词技术实现原理与关键源码
    支持向量机通俗导论(理解SVM的三层境界)
    用 Chrome 扩展实现修改
    可编辑表格
    在浏览器右键添加自定义菜单
  • 原文地址:https://www.cnblogs.com/jasenkin/p/draw_rectangle_round.html
Copyright © 2020-2023  润新知