前面我们讲了一个自定义控件完成的大体框架轮廓,我们不想每用到一个自定义控件都从零开始。所以今天,我们来建立一个基类,准备大干一场,让我们后面建立的控件都继承它。
一、建立基本控件
1、建立一个空的用户控件类
这里我们定义名称为UserControlBase,同样,我们一开始得到的是一个空类,里面什么都没有做的代码,如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HJComponent
{
public partial class UserControlBase: UserControl
{
public myControl()
{
InitializeComponent();
}
}
}
下面,我们来逐步对他进行改造,以便让它将来能够承担大任!
2、两个GDI+绘画相关的对象(Graphics和GraphicsPath)
不熟悉GDI+的可以参考以下我前面的博文《VS2017中的GDI+绘图轻松入门》,这里我们不再详细介绍。
我们知道在有PaintEventArgs参数的方法中,我们都可以通过这个参数获得GDI+的Graphic,我们可以用它来绘画。
当然,我们如果是在这里使用控件本身的CreateGraphics()方法获取的Graphic对象来绘制图形则会有一个毛病,拖放对象的时候则显示图形,一旦是去焦点则图形消失,但我们使用PaintEventArgs获取的Graphic则没有这个问题。
下面是利用PaintEventArgs代码:
//定义了一个绿色,宽度为的画笔
Pen p = new Pen(Color.Green, 1);
//在画板上画矩形,起始坐标为(this.Width / 4, this.Height/4),宽为,高为
e.Graphics.DrawRectangle(p, this.Width / 8, this.Height / 8, this.Width*3/4, this.Height*3/ 4);
下面是利用CreateGraphics()
Graphics grfc = this.CreateGraphics();
//定义了一个绿色,宽度为的画笔
Pen p = new Pen(Color.Green, 1);
//在画板上画矩形,起始坐标为(this.Width / 4, this.Height/4),宽为,高为
grfc.DrawRectangle(p, this.Width / 8, this.Height / 8, this.Width*3/4, this.Height*3/ 4);
3、绘制一个圆角矩形
int Radius = 20;
int x = 0;
int y = 0;
int width = this.Width;
int height = this.Height;
Pen pen = new Pen(Color.Green, 1);
GraphicsPath gp = new GraphicsPath();
gp.StartFigure();
//上边线
gp.AddLine(new PointF(x + Radius / 2, y), new PointF(x + width-1 - Radius / 2, y));
//右上角
gp.AddArc(new Rectangle(x + width-1 - Radius, y, Radius, Radius), 270, 90);
//右边线
gp.AddLine(new PointF(x + width-1, y + Radius / 2), new PointF(x + width-1, y + height - Radius / 2));
//右下角
gp.AddArc(new Rectangle(x + width -1- Radius, y + height - Radius-1, Radius, Radius), 0, 90);
//下边线
gp.AddLine(new PointF(x + Radius / 2, y + height-1), new PointF(x + width - Radius / 2, y + height-1));
//左下角
gp.AddArc(new Rectangle(x, y + height-1 - Radius, Radius, Radius), 90, 90);
//左边线
gp.AddLine(new PointF(x, y + Radius / 2), new PointF(x, y + height - Radius / 2));
//左上角
gp.AddArc(new Rectangle(x, y, Radius, Radius), 180, 90);
gp.CloseFigure();
e.Graphics.DrawPath(pen, gp);
上面我们使用了graphicsPath对象来进行连续绘图,它的绘图方式是以一条路径的方式将图形轮廓依次绘制完而形成一条封闭路径。最后再降这条路径用Graphics对象绘制出来。
这里要注意的就是绘制的起始坐标,对于一个控件而言,都是一块完整的绘图板,它的左上角都是(0,0)坐标,千万别用控件的location来获取坐标原点,否则你的图形不能显示到正确的位置,或者你几乎就没有机会看到它(靠近窗体左上角才能看到)
4、重载OnPaint
这个在第一篇博文中已经讲到过了,
我们这里引入using System.Drawing.Drawing2D;便于我们后面的图形绘制;
我们将上面的代码直接拷贝到OnPaint里面,运行就可以得到这样的一个控件
上面的颜色我们随便设置的,我们进一步将控件的边框和填充色修改一下,让它看起来更像一个按钮
Color Bcolor = Color.FromArgb(23, 140, 244); //初始边框颜色
Color Fcolor = Color.FromArgb(50, 116, 186, 247);////初始矩形内的填充色
二、完整代码
mycontrol.cs
public partial class myControl : UserControl
{
public myControl()
{
InitializeComponent();
base.SetStyle(ControlStyles.UserPaint, true);//使用控件自身来绘制而不是系统来绘制
base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);//忽略窗口绘制背景的消息,以减少闪烁
base.SetStyle(ControlStyles.DoubleBuffer, true);//启用绘图双缓冲机制,减少控件刷新时的闪烁
}
//重写该属性以设置控件默认大小
protected override System.Drawing.Size DefaultSize
{
get
{
return new Size(100, 40);
}
}
protected override void OnPaint(PaintEventArgs e)
{
#region 绘制圆角矩形
Color Bcolor = Color.FromArgb(23, 140, 244); //初始边框颜色
Color Fcolor = Color.FromArgb(50, 116, 186, 247);//初始矩形内的填充色
int x = 0;
int y = 0;
int width = this.Width;
int height = this.Height;
int Radius = 12;
Pen pen = new Pen(Bcolor, 1);
GraphicsPath gp = new GraphicsPath();
gp.StartFigure();
//上边
gp.AddLine(new PointF(x + Radius / 2, y), new PointF(x + width-1 - Radius / 2, y));
//右上角
gp.AddArc(new Rectangle(x + width-1 - Radius, y, Radius, Radius), 270, 90);
//右边
gp.AddLine(new PointF(x + width-1, y + Radius / 2), new PointF(x + width-1, y + height - Radius / 2));
//右下角
gp.AddArc(new Rectangle(x + width -1- Radius, y + height - Radius-1, Radius, Radius), 0, 90);
//下边
gp.AddLine(new PointF(x + Radius / 2, y + height-1), new PointF(x + width - Radius / 2, y + height-1));
//左下角
gp.AddArc(new Rectangle(x, y + height-1 - Radius, Radius, Radius), 90, 90);
//左边
gp.AddLine(new PointF(x, y + Radius / 2), new PointF(x, y + height - Radius / 2));
//左上角
gp.AddArc(new Rectangle(x, y, Radius, Radius), 180, 90);
gp.CloseFigure();
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillPath(new SolidBrush(Fcolor), gp);
e.Graphics.DrawPath(pen, gp); // e是PaintEventArgs
#endregion
}
}
designer.cs代码
partial class myControl
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region 组件设计器生成的代码
private System.Windows.Forms.Label txt;//声明一个label名称为txt
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
//
this.txt = new System.Windows.Forms.Label();
//
//txt的设计部分
//
this.txt.BackColor = System.Drawing.Color.Transparent;
this.txt.Dock = System.Windows.Forms.DockStyle.Fill;
this.txt.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.txt.ForeColor = System.Drawing.Color.White;
this.txt.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.txt.Location = new System.Drawing.Point(0, 0);
this.txt.Name = "text";
this.txt.Size = new System.Drawing.Size(184, 60);
this.txt.TabIndex = 0;
this.txt.Text = "自定义按钮";
this.txt.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.SuspendLayout();
//
// myControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ButtonFace;
this.Controls.Add(this.txt);//添加txt
this.Name = "myControl";
this.ResumeLayout(false);
}
#endregion
}
下一步,我们进行封装,请继续关注《C#自定义控件编程轻松入门(3)》!