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分别变换不同的圆角位置: