在TextBox控件底端显示下划线-C#学习进阶

实例说明

在填表单的时候,每一个空缺项都是以下划线的形式出现,此时如果在空缺的位置放置一个TextBox控件,看起来既不美观也不符合常理。本实例可以很好的解决此问题,实例运行结果如图:

在TextBox控件底端显示下划线-C#学习进阶

技术要点

本实例主要用到自定义类CustomTextBoxGroup,该类的功能是用来继承TextBox控件,并拓展原有控件的一些功能。在其构造方法中,定义控件的外观和位置。在重写Windows处理消息的函数中,捕获处理TextBox控件编辑颜色和绘制的消息,然后用自定义方法DrawBottomLines 绘制TextBox控件的下划线。本实例在实现绘制TextBox控件下划线的过程中,需要获取整个窗口的设备场景,因此用到Windows提供的API函数GetWindowDC和用于释放设备场景的API函数ReleaseDC,下面介绍本实例中用到的技术。

(1)CustomTextBoxGroup方法

该方法为类CustomTextBoxGroup的构造方法。其语法格式如下:

public CustomTextBoxGroup()

(2)WndProc方法

该方法用来捕获处理TextBox控件编辑颜色和绘制的消息。其语法格式如下:

 protected override void WndProc(ref Message m)
      {
         base.WndProc(ref m);               //处理消息
      }

(3)DrawBottomLines方法

该方法用来绘制TextBox控件的底端横线。其语法格式如下:

public void DrawBottomLines(Graphics g)

参数说明如下。

g:表示GDI+绘图图面对象。

返回值:该方法无返回值。

(4)GetWindowDC方法

该方法用来获取当前窗口的设备场景。其语法格式如下:

[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);

参数说明如下。

hWnd:表示要释放的设备场景相关的窗口句柄。

hDC:表示要释放的设备场景句柄。

返回值:执行成功返回1,否则,返回0。

注意:在本实例中用到Windows提供的API函数,因此用到System.Runtime.InteropServices命名空间。在进行TextBox控件的绘制操作时需要引用System.Drawing命名空间。

实现过程

(1)创建一个项目,将其命名为VisionUnderLine,修改默认窗体为VisionUnderLine。

(2)主要程序代码。

在窗体加载时,直接调用自定义类中的内容声明一个TextBox控件goal,并指定自定义控件goal的父容器为当前窗体,然后将控件添加至当前窗体。代码如下:

private void VisionUnderLine_Load(object sender,EventArgs e)
{
    System.Windows.Forms.TextBox goal = new CustomTextBoxGroup();    //定义一个TextBox对象goal
    goal.Parent = this;                       //获取或设置自定义TextBox控件的父容器
    this.Controls.Add(goal);               //向窗体中添加自定义TextBox控件goal
}

在自定义类CustomTextBoxGroup的构造方法中,首先定义TextBox控件的位置和大小。代码如下:

public CustomTextBoxGroup()

{

    this.Width = 180;                        //设置控件的宽度

    this.Height = 100;                        //设置控件的高度

    this.BorderStyle = BorderStyle.None;    //设置控件为无边框状态

    this.Top = 60;                           //设置控件上边缘与其容器工作区上边缘之间的距离

    this.Left = 100;                         //设置控件左边缘与其容器工作区左边缘之间的距离

}


在该类的内部需要对用到的一些变量进行声明。代码如下:

public const int WM_PAINT = 0x000F;             //该变量标识绘制TextBox控件

public const int WM_CTLCOLOREDIT = 0x0133;                   //该变量表示开始编辑TextBox控件的颜色

[DllImport("user32.dll")]

public static extern IntPtr GetWindowDC(IntPtr hWnd);// 获取整个窗口的设备场景

[DllImport("user32.dll")]

// 释放由调用GetDC或GetWindowDC函数获取的指定设备场景,它对类或私有设备场景无效

public static extern int ReleaseDC(IntPtr hWnd,IntPtr hDC);


重载Windows处理消息的函数WndProc,对相应的消息捕获后进行处理。代码如下:

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);                 //处理消息
    switch(m.Msg)                         //截获有关TextBox控件的绘制信息
    {
        case WM_CTLCOLOREDIT:              //当开始编辑TextBox控件的颜色时
            goto case WM_PAINT;        //跳转到TextBox控件的绘制
        case WM_PAINT:                //当开始绘制TextBox控件时
            IntPtr hDC = GetWindowDC(this.Handle);   //获取当前窗口的设备场景
            if(hDC.ToInt32() != 0)         //当此场景存在时
            {
                using(Graphics g = Graphics.FromHdc(hDC))           //声明一个GDI+绘图图面类对象g所占用的资源
                {
                    DrawBottomLines(g);    //绘制TextBox控件的底端横线
                    g.Dispose();    //释放GDI+绘图图面类对象g所占用的资源
                }
            }
            m.Result = IntPtr.Zero;         //指定在当前条件下的返回值
            ReleaseDC(m.HWnd,hDC);   //释放指定设备的场景
            break;
    }
}

当捕获绘制TextBox控件的消息后,需要绘制它的底端边框,此时用到DrawBottomLines方法。代码如下:

public void DrawBottomLines(Graphics g)
{
    Pen p = new Pen(this.BackColor,2);            //定义一个用于绘制直线和曲线的对象并设定它的颜色和宽度
    g.DrawRectangle(p,1,1,this.Width - 2,this.Height - 2);       //绘制由坐标对、宽度和高度指定的矩形
    p = new Pen(Color.FromArgb(0,0,0),1);      //定义一个用于绘制直线和曲线的对象并设定它的颜色和宽度
    g.DrawLine(p,0,this.Height - 1,this.Width,this.Height - 1);         //绘制TextBox的底端横线
    p.Dispose();                                //释放画笔p所占用的资源
}