C#自定义控件编程轻松入门(2)

本文介绍了如何在C#中创建一个自定义控件的基类,用于后续控件的继承。首先,创建了一个名为UserControlBase的空用户控件类,并逐步改造以支持GDI+绘图,包括如何使用Graphics和GraphicsPath绘制圆角矩形。接着,重载了OnPaint方法,展示了如何绘制边框和填充色,以实现一个类似按钮的外观。此外,还设置了控件的默认大小和双缓冲机制以减少闪烁。最后,提供了一段完整的代码示例,包括控件的绘制和设计器代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面我们讲了一个自定义控件完成的大体框架轮廓,我们不想每用到一个自定义控件都从零开始。所以今天,我们来建立一个基类,准备大干一场,让我们后面建立的控件都继承它。

一、建立基本控件

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)》!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河西石头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值