实现的功能包含:
1)实现一个椭圆的按钮。可居中显示一行文本。
2)鼠标离开按钮和进入按钮时,按钮边框和背景色需要发生变化。
实现步骤:
1)新增一个用户控件库。
public class UserButton:System.Windows.Forms.UserControl { }
2)定义控件属性:
private Color _borderColor = Color.Blue; /// <summary> /// 按钮边框色 /// </summary> [System.ComponentModel.Category("Appearance")] [System.ComponentModel.DefaultValue(typeof(Color),"Blue")] public Color BorderColor { get { return _borderColor; } set { _borderColor = value; } } private Color _backColor = Color.White; /// <summary> /// 按钮背景色 /// </summary> [System.ComponentModel.Category("Appearance")] [System.ComponentModel.DefaultValue(typeof(Color), "White")] public Color BackColor { get { return _backColor; } set { _backColor = value; } } private Color _hoverBorderColor = Color.Red; /// <summary> /// 鼠标悬停在按钮上方时的边框色 /// </summary> [System.ComponentModel.Category("Appearance")] [System.ComponentModel.DefaultValue(typeof(Color), "Red")] public Color HoverBorderColor { get { return _hoverBorderColor; } set { _hoverBorderColor = value; } } private Color _hoverBackColor = Color.RoyalBlue; /// <summary> /// 按钮背景色 /// </summary> [System.ComponentModel.Category("Appearance")] [System.ComponentModel.DefaultValue(typeof(Color), "RoyalBlue")] public Color HoverBackColor { get { return _hoverBackColor; } set { _hoverBackColor = value; } } private string _caption = string.Empty; /// <summary> /// 按钮文本 /// </summary> [System.ComponentModel.Category("Appearance")] [System.ComponentModel.DefaultValue(null)] public string Caption { get { return _caption; } set { _caption = value; } } /// <summary> /// 鼠标悬停标志 /// </summary> private bool bMouseHoverFlag = false;
3)添加相关事件
开发自定义控件可以绑定控件的Paint事件,也可以重写OnPaint方法。在重写OnPaint方法时一定要调用base.OnPaint方法。
OnPaint方法中,PaintEventArgs属性包含Graphics和ClipRectangle属性。Graphics可以看作需要绘制的画布,ClipRectangle是绘制区域剪切矩形。一般情况下,控件重新绘制内容时不需要重写所有的内容,而是绘制一部分内容。该参数指明控件中哪个部分是需要重新绘制的。该区域以外的界面不需要重新绘制,因此剪切矩形是优化图形界面软件性能的基础。
/// <summary> /// /// </summary> /// <param name="e"></param> protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { base.OnPaint(e); using (System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath()) { path.AddEllipse(0,0,this.ClientSize.Width-1,this.ClientSize.Height-1); if (bMouseHoverFlag) { //绘制背景 using (SolidBrush b = new SolidBrush(this.HoverBackColor)) { e.Graphics.FillPath(b, path); } //绘制边框 using (Pen p = new Pen(this.HoverBorderColor)) { e.Graphics.DrawPath(p, path); } } else { //绘制背景 using (SolidBrush b = new SolidBrush(this.BackColor)) { e.Graphics.FillPath(b, path); } //绘制边框 using (Pen p = new Pen(this.BorderColor)) { e.Graphics.DrawPath(p, path); } } if (this.Caption != string.Empty) { using (StringFormat f = new StringFormat()) { f.Alignment = System.Drawing.StringAlignment.Center; f.LineAlignment = System.Drawing.StringAlignment.Center; f.FormatFlags = System.Drawing.StringFormatFlags.NoWrap; using (SolidBrush b = new SolidBrush(this.ForeColor)) { e.Graphics.DrawString(this.Caption,this.Font,b,new RectangleF(0,0,this.ClientSize.Width,this.ClientSize.Height),f); } } } } }
关于ClientSize:称为控件的客户区域。控件区域包含两部分内容:客户区和非客户区。一般开发人员绘制的界面都在客户区域,处理客户区的鼠标事件,操作系统绘制的区域在非客户区,处理非客户区的鼠标事件。当控件不存在非客户区时如没有边框和滚动条时,客户区与非客户区同。
4)添加效果:
在用户控件中,界面区域是矩形的,而我们绘制的按钮是椭圆形的,因此客户区域的有些部分不属于椭圆形区域。当鼠标在客户区域时,要判断鼠标是否在椭圆形区域内,否则按钮动态效果大大折扣。我们需要编写一个判断鼠标在椭圆形区域的函数。
/// <summary> /// 检测释放鼠标悬停状态是否发生改变,若发生改变则重绘 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> private bool CheckMouseHover(int x, int y) { bool flag = false; using (System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath()) { path.AddEllipse(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1); flag = path.IsVisible(x,y); if (flag != bMouseHoverFlag) { bMouseHoverFlag = flag; this.Invalidate(); } } return flag; }
控件重绘有两个方法可以Invalidate,Refresh调用。Invalidate与Refresh的区别是向操作系统声明控件用户界面一部分货全部无效。但不会导致立即重绘而是延迟一段时间后才开始重绘界面,是一种异步操作,这个等待时间根据操作系统繁忙程度而定,而Refresh会立即重绘整个用户界面,是一种同步操作。