正常情况下,在开发.NET Windows应用程序时,我们都会用到System.Windows.Forms名字空间的控件。可供我们使用的控件很多,从Label、TextBox等简单的控件到MonthCalendar、ColorDialog等功能更丰富、更复杂的控件。尽管这些控件对于我们需要开发的大多数Windows应用程序已经足够好了,但有时我们也需要自己开发一些System.Windows.Forms名字空间不包括的控件。本篇文章将讲述如何使用VB.NET创建定制控件,尤其是在需要提供自己的图形用户接口时。
开发定制的控件并不困难。在开发定制控件时,我们可以使用现有的控件,或者对Control或UserControl类进行扩展。结合使用现有的控件使我们减少提供接口的麻烦,扩展Control或UserControl类意味着我们需要覆盖OnPaint方法,自己绘制图形用户接口。本篇文章中,我们由UserControl类派生了一个定制控件,UserControl类本身也是由继承Control类而生成的。因此读者需要对这二个类有一定的了解。
Control类非常重要,因为它是Windows可视化组件的父类,我们开发的定制类将是Control类的一个子类。我们的定制类一般不会直接由Control类派生而成,相反,一般是对UserControl类进行扩展。
Control类
Control类提供向Windows应用程序用户显示信息的类所要求的基本功能,它处理用户通过键盘和鼠标进行的输入,以及消息的分配和安全。更重要的是,Control类定义了控件的范围(位置和大小),尽管它不实现控件的绘制。
Windows表单控件使用了环境属性,因此其子控件的显示与其周围环境相似。缺省情况下,环境属性是由其父控件获得的,如果类没有父控件或者其环境属性没有设置,则控件试图通过Site属性设置环境属性的值。如果控件没有确定位置,不支持环境属性,或者AmbientProperties对象的属性没有设置,控件就会使用缺省值。一般情况下,控件的环境特性表示控件的一个特征,例如BackColor,它会传递给子控件。例如,缺省情况下,Button控件将具有与其父表单控件相同的BackColor环境属性。
许多Control类的属性、方法和事件都会不加变化地传递给子类。
Control类的属性
下面是Control类的一些最重要的属性
BackColor
控件的背景颜色,是由一个System.Drawing.Color对象表示的。我们可以使用如下所示的代码将一个System.Drawing.Color对象赋给该属性:
control.BackColor = System.Drawing.Color.Red
Enabled
一个表示该控件是否可用的布尔型值,缺省情况下其值为True。
Location
控件的左上角在其窗口中的位置,由一个System.Drawing.Point对象表示。
Name
控件的名字。
Parent
返回控件的父控件或容器的引用。例如,在一个表单中添加的控件的父控件就是该表单,下面的代码将Button1控件所在的表单的标题栏改为“Thank you.”:
Button1.Parent.Text = "Thank you."
Size
控件的大小,由System.Drawing.Size对象表示。
Text
与控件相关的字符串。例如,在Label控件中,Text属性就是显示在标签体上的字符串。
Control类的方法
下面是一些Control类最经常使用的方法
BringToFront
如果该控件在其他一些控件下面,完整地显示该控件。换一句话说,这一方法能够显示一个完整的控件。
CreateGraphics
获取控件的System.Drawing.Graphics对象,我们可以在其上利用System.Drawing.Graphics类的各种方法进行显示。例如,下面的代码获取名字为Button1的控件的Graphics图像,然后在按钮上划一条对角的绿线:
Imports System.Drawing
Dim graphics As Graphics = Button1.CreateGraphics
Dim pen As Pen = New Pen(Color.Green)
graphics.DrawLine(pen, 0, 0, _
Button1.Size.Width, Button1.Size.Height)
但是,用这种方法在控件上画图,所画的图像不是“永久”的。当控件或者包含控件的表单被重画时,用这种方式画的图像就会消失。
Focus
将焦点给予该控件,使它成为活动控件
Hide
将控件的Visible属性设置为False,使它不被显示出来。
GetNextControl
按Tab键控制次序返回下一个控件。
OnXXX
触发XXX事件。这里的XXX可以是Click、ControlAdded、ControlRemoved、DoubleClick、DragDrop、DragEnter、DragLeave、DragOver、Enter、GotFocus、KeyDown、KeyPress、KeyUp、LostFocus、MouseDown、MouseEnter、MouseHover、MouseLeave、MouseMove、MouseUp、Move、Paint、Resize和TextChanged。例如,调用控件的OnClick方法就会触发其Click事件。
Show
将控件的Visible属性设置为True,以显示该控件。
UserControl类
UserControl类提供一个可以用来创建其他控件的空控件,它是Control类的一个间接子类。由该控件派生的对象如下所示:
·System.Object
·System.MarshalByRefObject
·System.ComponentModel.Component
·System.Windows.Forms.Control
·System.Windows.Forms.ScrollableControl
·System.Windows.Forms.ContainerControl
·System.Windows.Forms.UserControl
UserControl类从ContainerControl类继承所有的标准位置和与内存处理有关的代码。在用户定制控件中还需要这些代码。
RoundButton控件
有了Control和UserControl这二个类,开发定制的Windows控件就是轻而易举的了。我们的定制类是通过继承UserControl类而生成的,由于UserControl也是由继承Control类而生成的,我们的定制类将会继承Control类的所有有用的方法、属性和事件。例如,由于是继承Control类生成的,我们的定制类会自动地拥有事件处理程序。
在开发定制控件时特别重要的一个问题是如何显示定制控件的用户界面。无论如何组织定制控件,需要注意的是,定制控件有时会重新显示。因此,当定制控件重绘时,必须重新绘制用户界面。考虑到控件每次重绘时,都会调用Control类的OnPaint方法,使用新的绘制定制控件用户界面的OnPaint方法覆盖该方法就能保证定制控件的保持一定的外观。
表1中的代码是一个名称为RoundButton的控件,在图1中,表单上有一个RoundButton定制控件,表2是其代码。我们需要作的工作基本上就是覆盖OnPaint方法。系统向该方法传递一个PaintEventArgs对象,从该方法中我们可以获得控件的System.Drawing.Graphics对象,然后使用它的方法绘制定制控件的用户界面。
表1:RoundButton控件
Imports System.Windows.Forms
Imports System.Drawing
Public Class RoundButton : Inherits UserControl
Public BackgroundColor As Color = Color.Blue
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim graphics As Graphics = e.Graphics
Dim penWidth As Integer = 4
Dim pen As Pen = New Pen(Color.Black, 4)
Dim fontHeight As Integer = 10
Dim font As Font = New Font("Arial", fontHeight)
Dim brush As SolidBrush = New SolidBrush(BackgroundColor)
graphics.FillEllipse(brush, 0, 0, Width, Height)
Dim textBrush As SolidBrush = New SolidBrush(Color.Black)
graphics.DrawEllipse(pen, CInt(penWidth / 2), _
CInt(penWidth / 2), Width - penWidth, Height - penWidth)
graphics.DrawString(Text, font, textBrush, penWidth, _
Height / 2 - fontHeight)
End Sub
End Class
表1中的代码非常地简单,简直令人不能相信。我们的定制类只有一个方法:OnPaint。简单地说,该方法传递一个PaintEventArgs对象,从中我们可以获得System.Drawing.Graphics对象。这一Graphics对象表示我们的定制控件的绘制区,无论在该Graphics对象上绘制什么东西,它都会显示为定制用户控件的界面。
在Windows的编程中,绘制图形时需要用到笔、画笔等对象,要书写文本,就需要字体对象。下面OnPaint方法中的代码创建了一个宽度为4的System.Drawing.Pen对象:
Dim penWidth As Integer = 4
Dim pen As Pen = New Pen(Color.Black, 4)
然后再创建一个高度为10的Arial Font对象:
Dim fontHeight As Int