回 帖 发 新 帖 刷新版面

主题:[原创]漫漫原创路 - 公共控件封装篇

通常我们在程序中使用了进度条、工具栏等公共控件,发布程序时都要带上一个OCX,显得有点麻烦。今天,就让我们用VB来封装一个进度条:ProgressBar,由于是源代码级控件,编译时会被编译进程序,不需要带上OCX,比较方便。闲话少讲,新建一个EXE工程,添加一个UserControl,把它的大小调成我们平时看到的滚动条大小,并更名为ProgressBar。

让我们分析一下封装公共控件的过程,首先要用CreateWindowsEx创建该控件(VB控件作为它的父窗口).当控件用户设置属性时,我们要发送消息通知控件作出更改。
ProgressBar主要有3个属性:最大值(Max)、最小值(Min)、当前值(Value),对应的消息有:PBM_SETRANGE32 PBM_SETPOS

OK,开始写代码

'首先,输入以下声明:
Private Const PROGRESSBAR_CLASS = "msctls_progress32"    '滚动条类名

Private Const EN_INVALIADPROPERTYVALUE = 380        'vb的错误号码

Private Const WS_CHILD = &H40000000
Private Const WS_VISIBLE = &H10000000

Private Const WM_USER = &H400
Private Const PBM_SETPOS = (WM_USER + 2)
Private Const PBM_SETRANGE32 = (WM_USER + 6)

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long

'其次,我们要声明属性的默认值和声明一些变量来储存属性值:
'默认值
Const m_def_Max = 100
Const m_def_Min = 0
Const m_def_Value = 40

'控件句柄
Private m_hwnd As Long

'属性值
Private m_Max As Long
Private m_Min As Long
Private m_Value As Long

'然后,我们输入核心代码:
'初始化时创建控件
Private Sub UserControl_Initialize()
    m_hwnd = CreateWindowEx(0, PROGRESSBAR_CLASS, PROGRESSBAR_CLASS, _
        WS_CHILD Or WS_VISIBLE, 0, 0, 0, 0, UserControl.hwnd, 0, App.hInstance, ByVal 0)
End Sub

'大小改变时调整控件
Private Sub UserControl_Resize()
    MoveWindow m_hwnd, 0, 0, UserControl.Width \ Screen.TwipsPerPixelX, _
        UserControl.Height \ Screen.TwipsPerPixelY, 1
End Sub

'最大值属性
Public Property Get Max() As Long
    Max = m_Max
End Property

Public Property Let Max(ByVal New_Max As Long)
    If New_Max < Me.Value Or New_Max > &HFFFF& Then Err.Raise EN_INVALIADPROPERTYVALUE
    m_Max = New_Max
    SendMessage m_hwnd, PBM_SETRANGE32, m_Min, ByVal m_Max
    PropertyChanged "Max"
End Property

'最小值属性
Public Property Get Min() As Long
    Min = m_Min
End Property

Public Property Let Min(ByVal New_Min As Long)
    If New_Min > Me.Value Or New_Min < 0 Then Err.Raise EN_INVALIADPROPERTYVALUE
    m_Min = New_Min
    SendMessage m_hwnd, PBM_SETRANGE32, m_Min, ByVal m_Max
    PropertyChanged "Min"
End Property

'当前值属性
Public Property Get Value() As Long
    Value = m_Value
End Property

Public Property Let Value(ByVal New_Value As Long)
    If New_Value < Me.Min Or New_Value > Me.Max Then Err.Raise EN_INVALIADPROPERTYVALUE
    m_Value = New_Value
    SendMessage m_hwnd, PBM_SETPOS, m_Value, ByVal 0
    PropertyChanged "Value"
End Property

'初始化属性值时设置属性为默认值
Private Sub UserControl_InitProperties()
    Me.Max = m_def_Max
    Me.Min = m_def_Min
    Me.Value = m_def_Value
End Sub

'读取保存的属性值
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    Me.Max = PropBag.ReadProperty("Max", m_def_Max)
    Me.Min = PropBag.ReadProperty("Min", m_def_Min)
    Me.Value = PropBag.ReadProperty("Value", m_def_Value)
End Sub

'保存属性值
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    Call PropBag.WriteProperty("Max", m_Max, m_def_Max)
    Call PropBag.WriteProperty("Min", m_Min, m_def_Min)
    Call PropBag.WriteProperty("Value", m_Value, m_def_Value)
End Sub

OK, 一个滚动条控件就完成了,是不是很简单? 把控件放到窗体上看一下效果:
[img]http://blog.programfan.com/upfile/200705/20070511202139.jpg[/img]

还有一个问题, 如果要使用公共控件,必须在EXE的DLL输入表中加上comctl32.dll,如果用了XP风格的话, 用常规的声明方式调用InitCommonControls是会出错的(请参阅http://www.programfan.com/club/showbbs.asp?id=223873),所以我用类型库的方式声明这个API(关于类型库,请参阅我的签名:漫漫原创路 - API类型库篇):
'引入Dll
Private Sub ImportCommctrlDll()
    InitCommonControls
End Sub
[img]http://blog.programfan.com/upfile/200705/20070511202158.jpg[/img]

至于XP风格的问题,请参阅论坛的其它帖子.

如果你掌握了上面的方法,你可以进一步完善控件的属性(因为这里只封装了3个主要属性,ProgressBar还有其它属性), 甚至你还可以封装所有其它公共控件(例如状态栏,工具栏,ListView, TreeView等等).

源码下载:[url]http://upload.programfan.com/upfile/200705112037157.rar[/url]

回复列表 (共1个回复)

沙发

我来回复

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