如果您见过本人的文章"Window简介(二) 如何拦截ComboBox
MouseMove"应可以了解SubClass的动作是针对某一个Window来动作,像上面的这个文章就告诉大家如何透过SubClass来让
ComboBox能侦测到MouseMove,而如果有一群ComboBox全要侦测到MouseMove那不就每一个ComboBox都要来做
SubClass的动作,有没有一次完成不要如此麻烦的呢?原则上这是使用SuperClass可完成,SuperClass的作法是:
1.取得原本Class的设定(如:原本ComboBox的设定),可用GetClassLong来取得 2.更动Class的设定,可用SetClassLong来设定 3.依新的设定Create控制项,而且唯有新Create出的控制项才有作用,旧有的没有受 影响。
再来看一下GetClassLong,SetClassLong的第一个叁数,它是hWnd,想想看,这是更动某一个Class的API,而不是只更动
某个Window的API,怎麽传入hWnd,没错,那是间接的作法,由hWnd可以得知那是属於哪一种Class的控制项,进而改变/取得
该hWnd所属Class类别的设定。那现在就出现一个问题,我们要先Create出一个Window(控制项)而後才能取得其hWnd,之後才下
SetClassLong来更动设定,而这个Window因为是在更动设定之前所造出来的,所以新的设定没有在这个Window上作用(这是Window
的作法,没有办法),所以我们说不得,只好将该Window Kill掉,之後Create的Window才是我们想要的。如果使用的是纯Window
API的设计,可能不用如此,而使用以下三个步骤:
1.取得Class的设定,使用GetClassInfoEx()取得,并记录下来 2.更动原先的记录,将之变成另外一个Class 3.注册该Class,并CreateWindow
但这样做,就没有vb的使用者介面,将Control项放到Form上那麽容易,一切都用API来做,我想没有人会如此吧?
所以啦,在VB的话,就只好使用物件阵列的作法,因为透过它,可以做到到动态新增、移除Control项的功能,不过正因它是事後才产生的,所以我们对之的控制相对的就要付出代价(如:位置的设定)。
注释:以下程式在module1.bas 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 Declare
Function SetClassLong Lib "user32" Alias "SetClassLongA" (ByVal hwnd As
Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Const GCL_WNDPROC = (-24) Public Const WM_MOUSEMOVE = &H200
Public preWinProc As Long
Public Function wndproc(ByVal hwnd As Long, ByVal Msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long 注释:以下程式会截取mouse move,处理完後,再将之送往原来的Window Procedure
If Msg = WM_MOUSEMOVE Then 注释:请处理Mouse Move的动作 Debug.Print "Combol Mouse Move , hwnd="; hwnd End If 注释:将之送往原来的Window Procedure wndproc = CallWindowProc(preWinProc, hwnd, Msg, wParam, lParam) End Function
注释:以下程式在Form1, form1中有一Combo1并事先设定其Index =1 Sub Form_Load() Dim ret As Long Combo1(1).Move 5, 5 注释:记录原本的Window Procedure的位址 preWinProc = GetClassLong(Combo1(1).hwnd, GCL_WNDPROC) 注释:设定Combo1的window Procedure到wndproc ret = SetClassLong(Combo1(1).hwnd, GCL_WNDPROC, AddressOf wndproc) 注释:动态产生两个Combo,Mouse在这两个Combo上才会侦测到MouseMove Load Combo1(2) Combo1(2).Move 5, 400 Combo1(2).Visible = True Load Combo1(3) Combo1(3).Move 5, 800 Combo1(3).Visible = True Debug.Print "Combo1(1).Hwnd="; Combo1(1).hwnd Debug.Print "Combo1(2).Hwnd="; Combo1(2).hwnd Debug.Print "Combo1(3).Hwnd="; Combo1(3).hwnd End Sub
Private Sub Form_Unload(Cancel As Integer) Dim ret As Long 注释:取消Message的截取,而使之又只送往原来的Window Procedure ret = SetClassLong(Combo1(1).hwnd, GCL_WNDPROC, preWinProc) End Sub
|