目錄
- 何謂子類化(subclassing)
- Visual Basic 6子類化的實現(xiàn)
- Visual Basic .NET子類化的實現(xiàn)
- 小結(jié)
1. 何謂子類化(subclassing)
眾所周知,Windows是一個基于消息的系統(tǒng),消息在Windows的對象之間進行著傳遞。子類化和Windows的鉤子機制存在于消息系統(tǒng)之中,我們可以利用這些機制來操縱、修改甚至丟棄那些在操作系統(tǒng)或是進程中傳遞的消息,以求改變系統(tǒng)的一些行為。子類化技術(shù)用來截取窗口或控件之間的消息,當然是消息在到達目的窗口之前完成的操作。這些被截獲的消息既可以保留也可以修改它們的狀態(tài),之后就繼續(xù)發(fā)送到目的地。子類化技術(shù)實現(xiàn)了一些正常情況下無法實現(xiàn)的功能,試想鼠標右鍵單擊TextBox,系統(tǒng)默認彈出Undo、Cut、Copy、Paste等菜單,我們就可以利用子類化技術(shù)來改變這個系統(tǒng)菜單。
簡單的說,子類化就是創(chuàng)建一個新的窗口消息處理過程,并將其插入到原先的默認窗口消息處理過程之前。
子類化分為三類:實例子類化(instance subclassing)—從窗口或控件的單一實例截獲消息,這種子類化技術(shù)最普遍;全局子類化(global subclassing)—能夠截獲從相同的窗口類創(chuàng)建出來的多個窗口或控件的消息;超類化(superclassing)—和全局子類化很類似,區(qū)別在于可以應用在新的窗口類上面。
2. Visual Basic 6子類化的實現(xiàn)
在Visual Basic 6子類化的實現(xiàn)中我將通過一段代碼的實例來介紹這一技術(shù)在VB6中的應用?,F(xiàn)在很多開發(fā)社區(qū)中經(jīng)常談到的一個話題就是界面開發(fā)如何Skin,這種技術(shù)有很多解決方式,如使用可以貼圖的控件或使用第三方開發(fā)的換膚ActiveX控件。其實Skin技術(shù)需要處理的是WM_DRAWITEM、WM_MEASUREITEM、WM_NCPAINT消息,這些消息的主要用途就是可以重畫控件和窗口的非客戶區(qū)。想要對這些VB6無法處理的消息進行編程就必須用到子類化,這些消息都會被發(fā)送到能夠自繪的控件的窗口上,因此下面的例子就是利用窗口子類化來重畫Button控件。
①創(chuàng)建工程
啟動Visual Basic 6同時創(chuàng)建一個標準EXE工程。
②窗口布局
在FORM1上放置3個Button控件,并將前兩個Button的Style屬性設置為1-Graphical,因為只有Style屬性設置為Graphical的Button才可以Owner-drawn。
③在窗體中錄入代碼
- 代碼
-
- Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->Private Sub Command3_Click()
-
- '通過Enabled屬性的控制,來顯示重畫控件在Unenabled狀態(tài)時的效果
- If Command1.Enabled Then
-
- Command1.Enabled = False
-
- Else
-
- Command1.Enabled = True
-
- End If
-
- End Sub
-
- Private Sub Form_Load()
-
- '安裝子類化入口
- Call Init(Me.hWnd)
-
- End Sub
-
- Private Sub Form_Unload(Cancel As Integer)
-
- '卸載子類化
- Call Terminate(Me.hWnd)
-
- End Sub
- ④加入一個模塊并錄入代碼
- Option Explicit
-
- ' -- 引用Win32Api –
- '得到默認的窗口消息處理過程的地址需要的API
-
- Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
-
- '設置一個新的窗口消息處理過程的地址需要的API
-
- Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
-
- '給指定的窗口消息處理過程傳遞消息需要的API
-
- Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
-
- '內(nèi)存拷貝
-
- Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
-
- Const GWL_WNDPROC = (-4&)
-
- Dim PrevWndProc&
-
- Private Const WM_DESTROY = &H2
-
- Private Const WM_DRAWITEM = &H2B
-
- Private Type RECT
-
- Left As Long
-
- Top As Long
-
- Right As Long
-
- Bottom As Long
-
- End Type
-
- 'WM_DRAWITEM需要處理的結(jié)構(gòu)體
-
- Private Type DRAWITEMSTRUCT
-
- CtlType As Long
-
- CtlID As Long
-
- itemID As Long
-
- itemAction As Long
-
- itemState As Long
-
- hwndItem As Long
-
- hdc As Long
-
- rcItem As RECT
-
- itemData As Long
-
- End Type
-
- ' Owner draw 常量
-
- Private Const ODT_BUTTON = 4
-
- ' Owner draw 動作
-
- Private Const ODA_DRAWENTIRE = &H1
-
- Private Const ODA_SELECT = &H2
-
- Private Const ODA_FOCUS = &H4
-
- ' Owner draw 狀態(tài)
-
- Private Const ODS_SELECTED = &H1
-
- Private Const ODS_GRAYED = &H2
-
- Private Const ODS_DISABLED = &H4
-
- Private Const ODS_CHECKED = &H8
-
- Private Const ODS_FOCUS = &H10
-
- '得到指定窗口的文本
-
- Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
-
- 'GDI相關API函數(shù),重畫Button時使用
-
- Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
-
- Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
-
- Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
-
- Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
-
- '色彩常量
-
- Const COLOR_SCROLLBAR = 0
-
- Const COLOR_BACKGROUND = 1
-
- Const COLOR_ACTIVECAPTION = 2
-
- Const COLOR_INACTIVECAPTION = 3
-
- Const COLOR_MENU = 4
-
- Const COLOR_WINDOW = 5
-
- Const COLOR_WINDOWFRAME = 6
-
- Const COLOR_MENUTEXT = 7
-
- Const COLOR_WINDOWTEXT = 8
-
- Const COLOR_CAPTIONTEXT = 9
-
- Const COLOR_ACTIVEBORDER = 10
-
- Const COLOR_INACTIVEBORDER = 11
-
- Const COLOR_APPWORKSPACE = 12
-
- Const COLOR_HIGHLIGHT = 13
-
- Const COLOR_HIGHLIGHTTEXT = 14
-
- Const COLOR_BTNFACE = 15
-
- Const COLOR_BTNSHADOW = 16
-
- Const COLOR_GRAYTEXT = 17
-
- Const COLOR_BTNTEXT = 18
-
- Const COLOR_INACTIVECAPTIONTEXT = 19
-
- Const COLOR_BTNHIGHLIGHT = 20
-
- Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
-
- Private Declare Function FrameRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
-
- Private Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
-
- '畫筆格式
-
- Const PS_SOLID = 0
-
- Const PS_DASH = 1 ' -------
-
- Const PS_DOT = 2 ' .......
-
- Const PS_DASHDOT = 3 ' _._._._
-
- Const PS_DASHDOTDOT = 4 ' _.._.._
-
- Const PS_NULL = 5
-
- Const PS_INSIDEFRAME = 6
-
- Const PS_USERSTYLE = 7
-
- Const PS_ALTERNATE = 8
-
- Const PS_STYLE_MASK = &HF
-
- Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long
-
- Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
-
- Private Type POINTAPI
-
- x As Long
-
- y As Long
-
- End Type
-
- Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
-
- Private Const DT_SINGLELINE = &H20
-
- Private Const DT_CENTER = &H1
-
- Private Const DT_VCENTER = &H4
-
- Private Declare Function SetTextColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
-
- Private Declare Function SetBkMode Lib "gdi32" (ByVal hdc As Long, ByVal nBkMode As Long) As Long
-
- Private Const TRANSPARENT = 1
-
- ' – 聲明結(jié)束 --
-
- Private Sub DrawButton(ByVal hWnd As Long, ByVal hdc As Long, rct As RECT, ByVal nState As Long)
-
- Dim P As POINTAPI
-
- Dim s As String
-
- Dim hbr As Long
-
- Dim hpen As Long
-
-
-
- hbr = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)) 'RGB(231, 231, 231)
-
- SelectObject hdc, hbr
-
- FillRect hdc, rct, hbr
-
- DeleteObject hbr
-
-
-
- '畫文字時背景為透明狀
-
- SetBkMode hdc, TRANSPARENT
-
- '得到Button的Caption
-
- s = String$(255, " ")
-
- GetWindowText hWnd, s, 255
-
- s = Trim$(s)
-
- '根據(jù)Button的Enabled狀態(tài)進行重畫
-
- If (nState And ODS_DISABLED) = ODS_DISABLED Then
-
- '畫外圍灰框
-
- hbr = CreateSolidBrush(RGB(132, 130, 132))
-
- SelectObject hdc, hbr
-
- FrameRect hdc, rct, hbr
-
- DeleteObject hbr
-
- '畫內(nèi)側(cè)3D效果->亮色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 1, rct.Top + 1
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Left + 1, rct.Bottom - 1
-
- DeleteObject hpen
-
- '畫內(nèi)側(cè)3D效果->暗色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(189, 190, 189))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Bottom - 2, P
-
- LineTo hdc, rct.Right - 1, rct.Bottom - 2
-
- MoveToEx hdc, rct.Right - 2, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 2, rct.Bottom - 1
-
- DeleteObject hpen
-
- '畫陰影文字
-
- rct.Left = rct.Left + 1
-
- rct.Right = rct.Right + 1
-
- rct.Bottom = rct.Bottom + 1
-
- rct.Top = rct.Top + 1
-
- SetTextColor hdc, GetSysColor(COLOR_BTNHIGHLIGHT)
-
- DrawText hdc, s, LenB(StrConv(s, vbFromUnicode)), rct, DT_CENTER Or DT_SINGLELINE Or DT_VCENTER
-
- rct.Left = rct.Left - 1
-
- rct.Right = rct.Right - 1
-
- rct.Bottom = rct.Bottom - 1
-
- rct.Top = rct.Top - 1
-
- SetTextColor hdc, GetSysColor(COLOR_GRAYTEXT)
-
- DrawText hdc, s, LenB(StrConv(s, vbFromUnicode)), rct, DT_CENTER Or DT_SINGLELINE Or DT_VCENTER
-
- Exit Sub
-
- End If
-
- '按下Button時重畫
-
- If (nState And ODS_SELECTED) = ODS_SELECTED Then
-
- '畫內(nèi)部區(qū)域顏色
-
- hbr = CreateSolidBrush(RGB(156, 186, 222))
-
- SelectObject hdc, hbr
-
- FillRect hdc, rct, hbr
-
- DeleteObject hbr
-
- '畫外圍灰框
-
- hbr = CreateSolidBrush(RGB(99, 125, 165))
-
- SelectObject hdc, hbr
-
- FrameRect hdc, rct, hbr
-
- DeleteObject hbr
-
- '畫內(nèi)側(cè)3D效果->亮色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(123, 158, 206))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 1, rct.Top + 1
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Left + 1, rct.Bottom - 1
-
- DeleteObject hpen
-
- '畫內(nèi)側(cè)3D效果->暗色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(181, 203, 231))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Bottom - 2, P
-
- LineTo hdc, rct.Right - 1, rct.Bottom - 2
-
- MoveToEx hdc, rct.Right - 2, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 2, rct.Bottom - 1
-
- DeleteObject hpen
-
-
-
- rct.Left = rct.Left + 1
-
- rct.Right = rct.Right + 1
-
- rct.Bottom = rct.Bottom + 1
-
- rct.Top = rct.Top + 1
-
- SetTextColor hdc, GetSysColor(COLOR_BTNTEXT)
-
- DrawText hdc, s, LenB(StrConv(s, vbFromUnicode)), rct, DT_CENTER Or DT_SINGLELINE Or DT_VCENTER
-
- Exit Sub
-
- End If
-
- 'Button得到焦點時重畫
-
- If (nState And ODS_FOCUS) = ODS_FOCUS Then
-
- '畫內(nèi)部區(qū)域顏色
-
- hbr = CreateSolidBrush(RGB(173, 203, 239))
-
- SelectObject hdc, hbr
-
- FillRect hdc, rct, hbr
-
- DeleteObject hbr
-
- '畫外圍灰框
-
- hbr = CreateSolidBrush(RGB(107, 138, 181))
-
- SelectObject hdc, hbr
-
- FrameRect hdc, rct, hbr
-
- DeleteObject hbr
-
- '畫內(nèi)側(cè)3D效果->亮色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(198, 223, 247))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 1, rct.Top + 1
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Left + 1, rct.Bottom - 1
-
- DeleteObject hpen
-
- '畫內(nèi)側(cè)3D效果->暗色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(132, 174, 222))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Bottom - 2, P
-
- LineTo hdc, rct.Right - 1, rct.Bottom - 2
-
- MoveToEx hdc, rct.Right - 2, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 2, rct.Bottom - 1
-
- DeleteObject hpen
-
-
-
- SetTextColor hdc, GetSysColor(COLOR_BTNTEXT)
-
- DrawText hdc, s, LenB(StrConv(s, vbFromUnicode)), rct, DT_CENTER Or DT_SINGLELINE Or DT_VCENTER
-
- Else
-
- '畫外圍灰框
-
- hbr = CreateSolidBrush(RGB(132, 130, 132))
-
- SelectObject hdc, hbr
-
- FrameRect hdc, rct, hbr
-
- DeleteObject hbr
-
- '畫內(nèi)側(cè)3D效果->亮色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 1, rct.Top + 1
-
- MoveToEx hdc, rct.Left + 1, rct.Top + 1, P
-
- LineTo hdc, rct.Left + 1, rct.Bottom - 1
-
- DeleteObject hpen
-
- '畫內(nèi)側(cè)3D效果->暗色
-
- hpen = CreatePen(PS_SOLID, 1, RGB(189, 190, 189))
-
- SelectObject hdc, hpen
-
- MoveToEx hdc, rct.Left + 1, rct.Bottom - 2, P
-
- LineTo hdc, rct.Right - 1, rct.Bottom - 2
-
- MoveToEx hdc, rct.Right - 2, rct.Top + 1, P
-
- LineTo hdc, rct.Right - 2, rct.Bottom - 1
-
- DeleteObject hpen
-
- '畫文字
-
- SetTextColor hdc, GetSysColor(COLOR_BTNTEXT)
-
- DrawText hdc, s, LenB(StrConv(s, vbFromUnicode)), rct, DT_CENTER Or DT_SINGLELINE Or DT_VCENTER
-
- End If
-
- End Sub
-
- '新的窗口消息處理過程,將被插入到默認處理過程之前
-
- Private Function SubWndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
-
- Dim di As DRAWITEMSTRUCT
-
- If Msg = WM_DESTROY Then Terminate (hWnd)
-
- '處理自畫消息
-
- If Msg = WM_DRAWITEM Then
-
- CopyMemory di, ByVal lParam, Len(di)
-
- '判斷是自畫Button
-
- If di.CtlType = ODT_BUTTON Then
-
- DrawButton di.hwndItem, di.hdc, di.rcItem, di.itemState
-
- '不返回VB的默認Button繪制過程
-
- SubWndProc = 1
-
- Exit Function
-
- End If
-
- End If
-
- '調(diào)用默認的窗口處理過程
-
- SubWndProc = CallWindowProc(PrevWndProc, hWnd, Msg, wParam, lParam)
-
- End Function
-
- '子類化入口
-
- Public Sub Init(hWnd As Long)
-
- PrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf SubWndProc)
-
- End Sub
-
- '子類化出口
-
- Public Sub Terminate(hWnd As Long)
-
- Call SetWindowLong(hWnd, GWL_WNDPROC, PrevWndProc)
-
- End Sub
-
- ' -- 模塊結(jié)束 -- '
3. Visual Basic .NET子類化的實現(xiàn) .NET中使用子類化技術(shù)要比VB6中簡單,因為微軟在.NET中已經(jīng)提供了接口,不需要我們再自己SetWindowLong了,我們做的是Overrides(覆蓋) WndProc過程即可。 Overrides Protected Sub WndProc( ByRef m As Message )參數(shù)m實現(xiàn)了Windows的消息類型。 下面的例子將演示如何將About加入窗口的系統(tǒng)菜單。 ①創(chuàng)建工程 創(chuàng)建一個VB.NET的Windows Application工程。 ②錄入代碼
- 代碼
-
- Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->Public Class Form1
-
- Inherits System.Windows.Forms.Form
-
- '中間隱去了.NET自動生成的代碼
- ' – 引用Win32Api
- Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As IntPtr, ByVal bRevert As Int32) As Int32
- Private Declare Function InsertMenu Lib "user32" Alias "InsertMenuA" (ByVal hMenu As Int32, ByVal nPosition As Int32, ByVal wFlags As Int32, ByVal wIDNewItem As Int32, ByVal lpNewItem As String) As Int32
-
- Private Const MF_BYCOMMAND = &H0&
- Private Const MF_BYPOSITION = &H400&
- Private Const MF_STRING = &H0&
- Private Const MF_SEPARATOR = &H800&
- Private Const WM_SYSCOMMAND = &H112
-
- Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
-
- InsertMenu(GetSystemMenu(Me.Handle, False), 0, MF_BYPOSITION Or MF_SEPARATOR, 2001, "") '加入一條分割線
-
- 'GetSystemMenu(Me.Handle, False)是得到系統(tǒng)菜單的句柄,第二個參數(shù)為True的話不能改變系統(tǒng)菜單,所以要設為False
- InsertMenu(GetSystemMenu(Me.Handle, False), 0, MF_BYPOSITION Or MF_STRING, 2002, "About Me(&A)") '加入About me菜單在系統(tǒng)菜單中
-
- End Sub
-
- Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
- '類化窗口--覆蓋WndProc過程
-
- If m.Msg = WM_SYSCOMMAND Then
-
- If m.WParam.ToInt32 = 2002 Then
-
- MsgBox("About Context", vbInformation, "About...")
-
- End If
-
- End If
-
- '調(diào)用窗口默認的處理過程
- MyBase.WndProc(m)
-
- End Sub
-
- End Class
4. 小結(jié) 子類化技術(shù)可以讓我們實現(xiàn)一些使用VB在正常條件下無法完成的任務,而且通過這些技術(shù)可以更為深入的學習Windows編程,成為VB開發(fā)人員中的高手。
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。