Winform控件优化之圆角Panel【绘制时需要注意的几点和扩展】

简介: 圆角的实现(原理和绘制方法)之前基本都已经介绍,本篇主要是实现圆角Panel时介绍几点注意点和一些扩展。一是BackColor应始终为Transparent;二是Draw完全显示绘制出的线条...

Winform控件优化之圆角Panel【绘制时需要注意的几点和扩展】

[toc]

圆角的实现(原理和绘制方法)之前基本都已经介绍,本篇主要是实现圆角Panel时介绍几点注意点和一些扩展。

新建RoundPanel.cs类文件,继承自Panle

public class RoundPanel : Panel{}

由于之前已经介绍圆角的实现,此处不再重复,只列出主要的点。

添加新窗体CustomPanelTest.cs,用于测试RoundPanel控件的使用和效果。

不要使用原控件BackColor属性的坑(BackColor应始终为Transparent)

在继承控件OnPaint方法或Paint事件中,重绘控件时有一个比较大的坑,那就是不要使用原控件的BackColor作为重绘时的背景色。

因为重绘的控件通常相对原Region长方形区域是不规则的,会有多出来的重绘之外的区域,除非完全用重绘区域内的路径范围创建新Region【但这又会产生锯齿和微不可见的白边】

在不新建Region的前提下,最正确的做法是设置扩展控件的背景色透明、无边框,然后重新绘制新背景和文字

比如,使用下面的代码在OnPaint方法中,你将永远看不到圆角效果(因为绘制的圆角图形和圆角外的其他部分各自颜色没有任何区别,看不出绘制的图形,被一样的背景色覆盖了)。

e.Graphics.DrawRoundRectAndCusp(new System.Drawing.Rectangle(0, 0, Width, Height), 15, BackColor);
DrawRoundRectAndCusp 为之前介绍的扩展方法,15为圆角半径。

基于此,可以在开启圆角绘制的情况下,实现对BackColor设置的限制,只能为Color.Transparent

半角半径属性RoundRadius大于等于0时,背景色透明。

[Category("Appearance"), Description("背景颜色,当RoundRadius>=0时取值为Color.Transparent,RoundRadius<0才可设置其他颜色")]
public override Color BackColor
{
    get => base.BackColor;
    set
    {
        if (RoundRadius >= 0)
        {
            base.BackColor = Color.Transparent;
        }
        else
        {
            base.BackColor = value;
        }
    }
}

绘制时使用圆角时的颜色属性roundNormalColor

e.Graphics.DrawRoundRectAndCusp(new System.Drawing.Rectangle(0, 0, Width, Height), 15, roundNormalColor);

Panel扩展控件实现圆角(Draw完全显示绘制出的线条)

Panel实现圆角和之前Button等介绍实现圆角的原理或过程没有任何区别。相对来说其需要的控件背景更少、也没有文字处理,反而更简单,只绘制个圆角即可。

本次实现边框是通过线条绘制(Graphics.DrawPath绘制路径线条、Graphics.DrawPolygon绘制points点坐标组成的线条)实现,在绘制路径时,默认是以路径为线条的中心,也就是路径内外个一半线条。而之前默认实现的圆角矩形路径正好是控件的范围,这就是导致路径外的一半线条超出控件,不会显示出来,产生一些问题。

if (borderPen != null)
{
    g.DrawPath(borderPen, path);
}

因此需要重新指定路径的范围,使其往内缩小半个BorderSize,从而绘制的线条完全显示(也可以修改线条绘制模式,使其在路径内层绘制)

但由于陷入了上面介绍的使用BackColor绘制背景的误区,以及,关于绘制Border的处理,将绘制路径减少roundBorderSize/2大小实现Draw完全显示线条,因此也单独做个记录。

整体减少roundBorderSize,开始位置移动roundBorderSize / 2

new Rectangle(ClientRectangle.X + roundBorderSize / 2, ClientRectangle.Y + roundBorderSize / 2, ClientRectangle.Width - roundBorderSize, ClientRectangle.Height - roundBorderSize)
Border绘制不完全显示出来的情况下,会导致不规格的圆角效果。

RoundPanel代码如下,关于扩展方法DrawRoundRectAndCusp、实现尖角效果等,可以查看之前的介绍。

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace CMControls
{
    public class RoundPanel : Panel
    {
        private Color roundNormalColor = SystemColors.Control;
        private int roundBorderSize = 0;
        private Color roundBorderColor = Color.MediumSlateBlue;
        private bool underlinedStyle = false;
        private int roundRadius = 20;

        /// <summary>
        /// 圆角按钮的半径属性
        /// </summary>
        [Category("Layout"), DefaultValue(20), Description("圆角半径,>=0时启用圆角按钮,等于0为直角,<0时使用默认控件样式")]
        public int RoundRadius
        {
            get { return roundRadius; }
            set
            {
                    roundRadius = value;
                    this.Invalidate();//Redraw control
            }
        }
        public override Color BackColor
        {
            get => base.BackColor;
            set
            {
                if (RoundRadius >= 0)
                {
                    base.BackColor = Color.Transparent;
                }
                else
                {
                    base.BackColor = value;
                }
            }
        }
        [CategoryAttribute("Appearance"),DefaultValue(typeof(Color), "SystemColors.Control"), Description("启用Radius圆角(RoundRadius>=0)时按钮标准颜色")]
        public Color RoundNormalColor
        {
            get { return roundNormalColor; }
            set
            {
                roundNormalColor = value;
                this.Invalidate();
            }
        }
        [CategoryAttribute("Appearance"), DefaultValue(0), Description("启用Radius圆角(RoundRadius>=0)时边框宽度,默认0")]
        public int RoundBorderWidth
        {
            get { return roundBorderSize; }
            set
            {
                roundBorderSize = value;
                this.Invalidate();

            }
        }
        [CategoryAttribute("Appearance"), DefaultValue(typeof(Color), "Color.MediumSlateBlue"), Description("启用Radius圆角(RoundRadius>=0)时边框颜色")]
        public Color RoundBorderColor
        {
            get => roundBorderColor;
            set
            {
                roundBorderColor = value;
                this.Invalidate();
            }
        }
        [CategoryAttribute("Appearance"), DefaultValue(false), Description("圆角边框宽度>0时,是否启用Underline,默认false")]
        public bool UnderlinedStyle
        {
            get { return underlinedStyle; }
            set
            {
                underlinedStyle = value;
                this.Invalidate();
            }
        }
        public RoundPanel()
        {
            BackColor = Color.Transparent;
        }
        //重写OnPaint
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (RoundRadius >= 0)
            {
                if (roundBorderSize > 0)
                {
                    using (var borderPen = new Pen(roundBorderColor, roundBorderSize))
                    {
                        if (underlinedStyle) //Line Style
                        {
                            e.Graphics.DrawLine(borderPen, 0, this.Height - roundBorderSize/2, this.Width, this.Height - roundBorderSize/2);
                        }
                        else
                        {
                            //borderPen.Alignment = PenAlignment.Inset;
                            e.Graphics.DrawRoundRectAndCusp(new Rectangle(ClientRectangle.X+ roundBorderSize / 2, ClientRectangle.Y+ roundBorderSize / 2, ClientRectangle.Width- roundBorderSize, ClientRectangle.Height - roundBorderSize), RoundRadius, roundNormalColor, borderPen: borderPen);
                        }
                    }
                }
                else
                {
                    e.Graphics.DrawRoundRectAndCusp(ClientRectangle, RoundRadius, roundNormalColor);
                }
            }
        }
    }
}

拖拽RoundPanel控件到窗体中,调整不同样式查看效果:

圆角模式,指定四个圆角的位置及组合

后面增加RoundMode属性,可以指定四个圆角的位置及其组合。

如下圆角Panel中的小圆角RoundPanel分别变换不同的圆角位置:

相关文章
|
6月前
|
前端开发 算法 JavaScript
从基础到进阶:实现div控件的拖拽和缩放功能
从基础到进阶:实现div控件的拖拽和缩放功能
95 0
|
API 图形学
Winform控件优化之自定义控件的本质【从圆角控件看自定义的本质,Region区域无法反锯齿的问题】
自定义控件的本质只有两点:重绘控件Region区域(圆角、多边形、图片等),这是整个控件的真实范围;重绘图形,在原有Region范围内,重绘不同的图形(圆角、多边形、图片等)作为背景......
562 0
Winform控件优化之自定义控件的本质【从圆角控件看自定义的本质,Region区域无法反锯齿的问题】
|
C# 容器
Winform控件优化之TabControl控件的美化和功能扩展
在基本的TabControl控件使用和功能之上,可以尝试对其进行美化和功能扩展,比如动态删除或添加tab、绘制图标按钮及鼠标hover时的背景变化、Tab从右向左布局的优化处理等。最重要...
2613 0
Winform控件优化之TabControl控件的美化和功能扩展
|
算法 Windows
Winform控件优化之实现无锯齿的圆角窗体(或任意图形的无锯齿丝滑的窗体或控件)【借助LayeredWindow】
在一般能搜到的所有实现圆角窗体的示例中,都有着惨不忍睹的锯齿...而借助于Layered Windows,是可以实现丝滑无锯齿效果的Form窗体的,其具体原理就是分层窗体....
1585 0
Winform控件优化之实现无锯齿的圆角窗体(或任意图形的无锯齿丝滑的窗体或控件)【借助LayeredWindow】
你听我说-HandyControl调整样式色系
你听我说-HandyControl调整样式色系
266 0
|
6月前
[Qt5&布局] 控件自动填满所在布局框架
[Qt5&布局] 控件自动填满所在布局框架
100 0
[Qt5&布局] 控件自动填满所在布局框架
|
算法 API C#
Winform控件优化之圆角按钮【各种实现中的推荐做法】(下)
最终优化实现ButtonPro按钮(继承自Button),既提供Button原生功能,又提供扩展功能,除了圆角以外,还实现了圆形、圆角矩形的脚尖效果、边框大小和颜色、背景渐变颜色...
1885 0
Winform控件优化之圆角按钮【各种实现中的推荐做法】(下)
|
C# 图形学
Winform控件优化之Paint事件实现圆角组件(提取绘制圆角的扩展方法)
Paint事件方法中实现圆角控件不要通过事件参数`e.ClipRectangle`获取控件区域范围,原因见最后介绍;注意设置控件背景透明(参见[Winform控件优化之背景透明那些事2...
817 0
Winform控件优化之Paint事件实现圆角组件(提取绘制圆角的扩展方法)
|
C# 图形学 Windows
Winform控件优化之圆角按钮【各种实现中的推荐做法】(上)
Windows 11下所有控件已经默认采用圆角,其效果更好、相对有着更好的优化...尝试介绍很常见的圆角效果,通过重写控件的OnPaint方法实现绘制,并在后面进一步探索对应的优化和可能的问题
1379 0
Winform控件优化之圆角按钮【各种实现中的推荐做法】(上)
|
前端开发 Android开发 开发者
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
370 0
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)