回 帖 发 新 帖 刷新版面

主题:[原创]打造自己的多风格按纽--用户控件制作详解(1)

打造自己的多风格按纽--用户控件制作详解(1)

  我相信各位与我一样,经常在网上看到别人发布的多彩多姿的按纽控件,但总有不尽如意的地方,
那么,就让我们自己来制作多风格的按纽控件,一起来体验成功的乐趣吧!
  为了便于表述,下面把在用户控件页面中进行的设计活动称为“控件设计”,把在窗体页面中进行
的设计活动称为“程序设计”,把进行程序设计的程序员称为“中间用户”,把最后使用程序的用户称
为“最终用户”。
  制作这个按纽控件要达到的目的:形状多样(共有21种形状),背景颜色多样,文本标题显示多样
(运用字符显示特技),能够显示真彩图片。
  新建一个工程,添加一个窗体(用于测试用户控件),再添加 ActiveX控件,这个控件就是用户控
件,也就是我们的工作对象。这时在工程管理器中可以看到工程多出了一个类别:UserControls,窗体
在 Forms列表中,而用户控件在 UserControls 列表中。好,我们在用户控件的属性窗口中将它的名称
改一下,就叫 PrettyCmd 吧,再将它的另外几个属性改一下:
①ScaleMode=3,因为我们会在代码中使用 API 函数来改变它的形状,而 API 函数是以“象素”为单
 位的;
②BackColor=绿色,你可以改为其它任何颜色,这只是为了以后做试验时能与窗体的背景区别开来;
③AutoRedraw=True
④ScaleWidth=2520
⑤ScaleHeight=1035
  其它属性暂时不加理会。
  现在可以使用窗体设计器在这个用户控件上面随便放些其它东西,例如图片框或者标签什么的,就
像一个窗体一样,但是注意这个“窗体”实际上它将成为中间用户在程序设计时控件的外观形状,我们
现在是在做按纽控件试验,就不必添加别的控件了。
  在 UserControl页面的代码编辑器中你也可以发现,设计一个用户控件时跟设计窗体是很相似的,
只是对象变成用户控件,Form 对象现在变成 UserControl 对象,触发的事件不一样而已。

一、自制多风格按纽的形状外观

  自制按纽一个很重要的原因就是我们想获得各种形状,所以首先让我们来设计它的形状。
  中间用户在进行程序设计时,常要在控件的某些属性的下拉列表中进行选择,我们要自制的按纽共
有18种形状(实际是21种形状,因为其中的“圆角矩形”可以变化出矩形、圆角矩形、椭圆形、圆形等
四种形状,如何变化以后会讲到),所以也必须能够供中间用户选择,那么,在控件设计阶段时,就要
在 UserControls 页面的代码窗口的 Option Explicit 节中输入以下代码:

Public Enum mState
  圆角矩形
  左斜下角
  左斜上角
  右斜下角
  右斜上角
  上斜左角
  上斜右角
  下斜左角
  下斜右角
  两边平行左斜
  两边平行右斜
  上下平行左斜
  上下平行右斜
  菱形
  上三角形
  下三角形
  左三角形
  右三角形
End Enum

  注意:
①如果你设计的控件的其它属性,其属性值不需要用下拉框加以选择的话,就不要在此进行类似定义。
②属性值我这写的都是汉字,以后中间用户打开这个属性的下拉框时看到也是汉字,如果你的英文很过
关,改为英文当然也可以。
③这个属性是公用的,要用 Public 来定义。

  这样的定义方法是不是有点象程序设计时的用户自定义数据类型?mState是它的名称。另外,我们
还要声明一个变量 vState 来表示中间用户所选择的属性值。还有,为了打造出这些形状,必须借助于
 API 函数,这些 API 函数必须事先声明。
  下面在 Option Explicit 节中继续输入:

'创建多边形
Private Declare Function CreatePolygonRgn Lib "gdi32" (lpPoint As POINTAPI, ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long
'创建圆角矩形
Private Declare Function CreateRoundRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, ByVal X3 As Long, ByVal Y3 As Long) As Long
'改变窗口的区域
Private Declare Function SetWindowRgn Lib "user32" (ByVal hwnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
'删除GDI对象
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private Type POINTAPI
  x As Long
  y As Long
End Type

Dim vState As Integer 

  再输入以下过程代码:

Private Sub DrawButton() '绘制按纽形状
Select Case vState
  Case 0 '圆角矩形
    DrawRoundCorner
  Case 1 To 13 '四边形
    DrawParallelogram
  Case 14 To 17 '三角形
    DrawDiagonal
End Select
End Sub

Private Sub DrawDiagonal() '三角
Dim pt(0 To 2) As POINTAPI, hRgn As Long
Select Case vState
  Case 14 '上三角
    pt(0).x = UserControl.ScaleWidth / 2: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = UserControl.ScaleHeight
    pt(2).x = 0: pt(2).y = UserControl.ScaleHeight
  Case 15 '下三角
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth / 2: pt(2).y = UserControl.ScaleHeight
  Case 16 '左三角
    pt(0).x = 0: pt(0).y = UserControl.ScaleHeight / 2
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
  Case 17 '右三角
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = UserControl.ScaleHeight / 2
    pt(2).x = 0: pt(2).y = UserControl.ScaleHeight
End Select
hRgn = CreatePolygonRgn(pt(0), 3, 1) '创建一个由3个点围成的区域
SetWindowRgn UserControl.hwnd, hRgn, True
DeleteObject hRgn
End Sub

Private Sub DrawRoundCorner() '圆角矩形
Dim hRgn As Long
hRgn = CreateRoundRectRgn(0, 0, UserControl.ScaleWidth, UserControl.ScaleHeight, 10, 10)
SetWindowRgn UserControl.hwnd, hRgn, True
DeleteObject hRgn
End Sub

Private Sub DrawParallelogram() '四边形
Dim pt(0 To 3) As POINTAPI, hRgn As Long
Select Case vState
  Case 1 '左下斜
    pt(0).x = UserControl.ScaleWidth / 3: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 2 '左上斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = UserControl.ScaleWidth / 3: pt(3).y = UserControl.ScaleHeight
  Case 3 '右下斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth * 2 / 3: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 4 '右上斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth * 2 / 3: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 5 '上左斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = UserControl.ScaleHeight / 3
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 6 '上右斜
    pt(0).x = 0: pt(0).y = UserControl.ScaleHeight / 3
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 7 '下左斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight * 2 / 3
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 8 '下右斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight * 2 / 3
  Case 9 '两边平行左斜
    pt(0).x = 0: pt(0).y = UserControl.ScaleHeight / 3
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight * 2 / 3
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 10 '两边平行右斜

    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = UserControl.ScaleHeight / 3
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight * 2 / 3
  Case 11 '上下平行左斜
    pt(0).x = UserControl.ScaleWidth / 3: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth * 2 / 3: pt(2).y = UserControl.ScaleHeight
    pt(3).x = 0: pt(3).y = UserControl.ScaleHeight
  Case 12 '上下平行右斜
    pt(0).x = 0: pt(0).y = 0
    pt(1).x = UserControl.ScaleWidth * 2 / 3: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight
    pt(3).x = UserControl.ScaleWidth / 3: pt(3).y = UserControl.ScaleHeight
  Case 13 '菱形
    pt(0).x = 0: pt(0).y = UserControl.ScaleHeight / 2
    pt(1).x = UserControl.ScaleWidth / 2: pt(1).y = 0
    pt(2).x = UserControl.ScaleWidth: pt(2).y = UserControl.ScaleHeight / 2
    pt(3).x = UserControl.ScaleWidth / 2: pt(3).y = UserControl.ScaleHeight
End Select
hRgn = CreatePolygonRgn(pt(0), 4, 1) '创建一个由4个点围成的区域
SetWindowRgn UserControl.hwnd, hRgn, True
DeleteObject hRgn
End Sub


  为了在程序设计时能够设置和显示这个属性,我们还必须添加有关的代码,也可以通过“工具”菜
单的“添加过程”来添加然后修改。如果通过菜单添加,VB其实是自动为你写几行固定格式的代码,免
去你手工输入的麻烦,我们就通过菜单来添加吧。
  选择“工具→添加过程”,跳出一个对话框,然后在单选按纽中选择“属性”,再在“名称”栏中
输入一个名字:State(在窗体页面的相关控件的属性窗口中会显示出这个属性名),点击确定,VB 就
会自动生成几行这样的代码:

Public Property Get state() As Variant
End Property

Public Property Let state(ByVal vNewValue As Variant)
End Property

  Get 和 Let 是两个相对的属性过程(注意它们都是公用的),它们都是供中间用户在程序设计阶
段使用的:Get 过程是当中间用户在窗体页面点击窗体上的按纽控件时被激活,显示该属性的值,你可
以在里面写一些适当的运算然后把结果赋给该属性名,就像函数一样;Let 过程是当中间用户在窗体页
面的“属性”窗口修改完按纽控件的属性值后被激活,修改该属性的值,vNewValue 是被赋的值(这个
变量名是可以修改的),你可以把得到的 vNewValue的值按自己的需要作任何用途。如果你手动输入上
面的代码,你要确保 Get 和 Let 后面的属性名应该相同,有关的数据类型也要相同,如果你是通过自
动生成得到代码的,那么要注意修改数据类型。如果你想建一个只读的属性,只要把 Let过程删除就行
了。我们就修改成如下的代码吧:

Public Property Get State() As mState '取得vState的值显示给中间用户
State = vState
End Property

Public Property Let State(ByVal vNewValue As mState) '把中间用户的输入值设置到按纽控件内部
vState = vNewValue
PropertyChanged "state"
DrawButton
End Property

  注意在 Let过程中调用了 DrawButton过程,有了这一句,那么中间用户在 PrettyCmd 的 State属
性下拉框中选择了某一种形状后,对应的按纽就会立即在对象窗口中改变为相应的形状。
  你还会发现 Let过程中有一句 PropertyChanged "state",PropertyChanged 方法是用户控件特有
的,用来通知属性编辑器:“喂,这里有一个属性值被改变了,麻烦你处理一下!”于是系统会根据需要
记录下这个被改变的属性值,以便进一步处理(通常是保存该值),后面带的参数 state 是属性名。
  这样处理之后,控件就能改变属性了。现在你点击 UserControl页面的代码窗口右上角的“×”以
及对象窗口右上角的“×”,退出控件设计,进入程序设计,调出 Form1的对象窗口和工具箱,这时你
会发现工具箱中多了一个名为 PrettyCmd的控件,这就是我们刚才自己制作的按纽控件了。把它画到窗
体上,就可以看到控件的属性窗口中已经有了一个具有下拉框的 state属性。改变这个属性值,窗体上
的按纽也随之改变了形状,哈哈!
  今天的实验就到这里吧,明天接着做。最后请运行一次,保存我们的成果。UserControl 是以普通
的文本文件格式存储的,该文件包含 UserControl 以及它的构成控件源代码和属性值。在 VB中这个文
件的扩展名为 .ctl,以后控件中要用到图形元素,VB 会就将它存放在同名的 .ctx 文件中。

附件中是按纽样品图片

回复列表 (共10个回复)

沙发

界面不错,支持!

板凳

先赞一个!
然后收藏,慢慢学习。

3 楼

支持!
我是界面白痴,又非常懒得做特效界面。
秋水兄真有出教科书的潜质,哪个出版商能慧眼识英才,速度啊!

4 楼

没看到颜色方面代码
这个只是一个控件区域控制代码.
不知道是不是用Line画的线.
色彩立体感不强.
希望看到速度快、质量高渐变色.

5 楼

顶一个,收藏...

6 楼

鼎鼎顶

7 楼

小菜鸟,学习了

8 楼

up

[img]http://upload.programfan.com/upfile/200711201208888.rar[/img]

9 楼

顶  学习

10 楼

只看到了按钮的一种状态下的样式,不知道按钮六态处理怎么样。

我来回复

您尚未登录,请登录后再回复。点此登录或注册