本帖最后由 东风破 于 2014-5-5 11:15 编辑
原转帖地址:http://www.autoitx.com/forum.php?mod=viewthread&tid=111&fromuid=7662117
很多人都对系统消息比较陌生,实际上,Autoit里用GUIGetMsg和GUICtrlSetOnEvent函数捕捉的GUI事件都属于系统消息的范畴。而在v3.1.0以后的版本里,我们就可以用GUIRegisterMsg函数来自行捕捉系统消息,藉此来实现对右击、双击、获取焦点等行为的判断。本文将探讨如何在Autoit里捕捉并处理GUI通知。
先看一下下面的例子,这个例子实现了对双击列表框的响应:GUICreate("MyGUI", 359, 94, -1, -1)
$list = GUICtrlCreateListView("ddddddddddd", 10, 10, 320, 80)
Global Const $WM_NOTIFY = 0x004E
GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")
GUISetState()
Do
Until GUIGetMsg() = -3
Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
#forceref $hWndGUI, $MsgID, $wParam
Local Const $NM_FIRST = 0
Local Const $NM_DBLCLK = ($NM_FIRST - 3)
Local $tagNMHDR, $event, $hwndFrom, $code
$tagNMHDR = DllStructCreate("int;int;int", $lParam) ;NMHDR (hwndFrom, idFrom, code)
If @error Then Return
$event = DllStructGetData($tagNMHDR, 3)
If $event = $NM_DBLCLK Then MsgBox(0, "", "双击")
$tagNMHDR = 0
$event = 0
$lParam = 0
EndFunc ;==>WM_Notify_Events
下面对整段代码进行分析:
Global Const $WM_NOTIFY = 0x004E
这一句是对系统消息的赋值,和一些高级语言不同,Autoit的库里并不包含系统消息,如果我们想要使用某一消息就必须先对其赋值。
类似的,我们在建立GUI时都会加上一句#include <GUIConstants.au3>,而GUIConstants.au3里就是对GUI样式的赋值。
另外,你可以使用 Win32 API Constants 这个工具来查看不同系统消息的值。
GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")
注册WM_NOTIFY这个消息ID(message),每当有新的通知(notification)产生时就会执行WM_Notify_Events这个函数。要捕捉不同的系统通知就需要注册不同的消息ID,类似的消息ID还有WM_COMMAND、WM_COMMNOTIFY等。
注意,我在描述系统消息时都没有加上$号,给变量加$号貌似是Autoit的特色,在后文提到系统消息时我都会省略掉$号。
Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
...
EndFunc ;==>WM_Notify_Events
每当有新的通知产生时这个函数就会被执行,其中$wParam就是发送通知的控件ID,而$event就是被触发的通知。
还有一点很重要,不同的消息ID传递的参数意义也不同,后文会继续提到。
If $event = $NM_DBLCLK Then MsgBox(0, "", "双击")
如果系统通知是双击就弹出对话框,你还可以用$wParam来判断具体控件。
经过上面的阅读相信大家对系统消息处理的基本原理有了了解,下面我们将了解到如何找到并使用我们想要的系统消息。
所有的GUI通知我们都可以在MSDN的控件页面下找到,地址是:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773173(v=vs.85).aspx
GUI通知分为两类,一类是通用的,一类是专门针对某一种控件的。通用消息可以在旁边侧栏里的General Control Reference下找到,其余的通知直接往下翻,然后点开不同的控件类型就是了。
前文我已说到,不同的系统通知需要注册不同的消息ID,具体的对应关系我们也可以在MSDN上找到。
比如NM_DBLCLK通知,在MSDN上是这样描述的:
Notifies a control's parent window that the user has double-clicked the left mouse button within the control. NM_DBLCLK is sent in the form of a WM_NOTIFY message.
也就是说需要注册WM_NOTIFY这个消息ID。
再如LBN_SETFOCUS通知,我们可以找到这样几句话:
An application sends the LBN_SETFOCUS notification message when a list box receives the keyboard focus. The parent window of the list box receives this notification message through the WM_COMMAND message.
这自然是说需要注册WM_COMMAND这个消息。
最后还剩下一个问题,就是不同的消息ID传递的参数不同,具体信息需要我们在MSDN里搜索。
比如说WM_NOTIFY这个消息,我们搜索到的描述页面是http://msdn.microsoft.com/en-us/library/windows/desktop/bb775583(v=vs.85).aspx。里面有这样的描述:
lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) WM_NOTIFY, // message ID
(WPARAM) wParam, // = (WPARAM) (int) idCtrl;
(LPARAM) lParam // = (LPARAM) (LPNMHDR) pnmh;
);
也就是说$wParam变量返回控件ID,而$lParam则包含了我们想要的通知类型。
再往下翻,有这样的话:
pnmh
Pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this parameter points to a larger structure that has the NMHDR structure as its first member.
也就是说$lParam这个变量为NMHDR结构,我们这样分解$lParam:
$tagNMHDR = DllStructCreate("int;int;int", $lParam) ;NMHDR (hwndFrom, idFrom, code)
$event = DllStructGetData($tagNMHDR, 3)
这样我们就可以由$event得到具体的通知类型。
另外我们还需要明晰一下概念,像NM_DBLCLK、NM_RCLICK、CBN_SELCHANGE之类的属于通知(notification),而WM_COMMAND、WM_NOTIFY等则属于消息(message)。
再看到下面一个例子:
GUICreate("MyGUI", 359, 94, -1, -1)
$list = GUICtrlCreateLabel("ddddddddddd", 10, 10, 320, 80)
Global Const $WM_COMMAND = 0x0111
GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = -3
ExitLoop
Case Else
;;;
EndSelect
WEnd
Func MY_WM_COMMAND($hWnd, $msg, $wParam, $lParam)
Local $nNotifyCode = BitShift($wParam, 16)
Local $nID = BitAND($wParam, 0xFFFF)
Local $hCtrl = $lParam
Local Const $STN_DBLCLK = 1
If $nNotifyCode = $STN_DBLCLK Then MsgBox(0, "", "双击")
EndFunc ;==>MY_WM_COMMAND
在这个例子里我想要捕捉文字控件的双击通知,在Static Controls里我得知双击通知是STN_DBLCLK,而我需要注册WM_COMMAND消息。
在WM_COMMAND里我又找到了下面的话:
WM_COMMAND wNotifyCode = HIWORD(wParam);
wID = LOWORD(wParam);
hwndCtl = (HWND) lParam;
即$lParam是控件ID,而$wParam包含了通知类型。再看下面的话:
wNotifyCode
Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0.
可知我们就需要用下面的代码分解$wParam:
Local $nNotifyCode = BitShift($wParam, 16)
这样$nNotifyCode 里就储存了通知类型。
最后我们就用下面的代码来提示双击操作:
If $nNotifyCode = $STN_DBLCLK Then MsgBox(0, "", "双击")
看了上面的例子相信大家已经能够熟练处理GUI通知,最后我再给出一个例子供大家举一反三:
拖动滚动条设置窗口透明度:
$gui = GUICreate("MyGUI", 392, 86, -1, -1)
$Slider_1 = GUICtrlCreateSlider(30, 10, 340, 60)
GUICtrlSetLimit($Slider_1, 255)
GUICtrlSetData($Slider_1, 255)
Global Const $WM_HSCROLL = 0x114
Global Const $TB_LINEUP = 0
Global Const $TB_LINEDOWN = 1
Global Const $TB_PAGEUP = 2
Global Const $TB_PAGEDOWN = 3
Global Const $TB_THUMBPOSITION = 4
Global Const $TB_THUMBTRACK = 5
GUIRegisterMsg($WM_HSCROLL, "MY_WM_HSCROLL")
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = -3
ExitLoop
Case Else
;;;
EndSelect
WEnd
Func MY_WM_HSCROLL($hWnd, $msg, $wParam, $lParam)
$nScrollCode = BitAND($wParam, 0x0000FFFF)
$nPos = BitShift($wParam, 16)
$hwndScrollBar = $lParam
Switch $nScrollCode
Case $TB_LINEDOWN, $TB_LINEUP, $TB_PAGEDOWN, $TB_PAGEUP, $TB_THUMBTRACK
WinSetTrans($gui, "", GUICtrlRead($Slider_1))
EndSwitch
EndFunc ;==>MY_WM_HSCROLL
ps.本来想多给几个例子的,不过再给文章长度就会超过限制...下周我还会继续讲解系统消息的其他应用。
|
|