旅途

如果想飞得高,就该把地平线忘掉

让一组相同的控制项有相同的行为(SuperClass)

   如果您见过本人的文章"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


posted on 2007-07-18 00:32 旅途 阅读(148) 评论(0)  编辑 收藏 引用 所属分类: 深入windows


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理