WM_MOUSELEAVE消息问题[已解决]
本帖最后由 3mile 于 2011-3-27 13:05 编辑如果鼠标不经过窗体内控件的话,自动隐藏是正常的.但只要鼠标悬停在控件上,窗体不停的隐藏,显示.
如果MouseGetPos()加入主循环,倒是可以完成.但总觉得这样效率太差,不考虑使用这个方法.
各路神仙快显灵!
#include <WindowsConstants.au3>
#include <winapiex.au3>
$form1=GUICreate('Form1',400,500,-1,0,$WS_POPUP,BitOR($WS_EX_TOPMOST,$WS_EX_TOOLWINDOW))
GUICtrlCreateButton("ok",10,10)
GUISetState()
GUIRegisterMsg(0x0200, 'WM_MOUSEMOVE')
GUIRegisterMsg(0x02A3, 'WM_MOUSELEAVE')
While GUIGetMsg() <> -3
WEnd
Func WM_MOUSEMOVE($hWndGUI, $MsgID, $wParam, $lParam)
local $win_pos=WinGetPos("Form1")
for $i=$win_pos to $win_pos step 10
if $i>=5 then ExitLoop
WinMove("Form1","",$win_pos,$i,$win_pos,$win_pos)
sleep(10)
Next
_WinAPI_TrackMouseEvent($form1,$TME_LEAVE)
EndFunc ;==>WM_MOUSEMOVE
Func WM_MOUSELEAVE($hWndGUI, $MsgID, $wParam, $lParam)
local $win_pos=WinGetPos("Form1")
if$win_pos>=0 then
for $i=$win_pos to $win_pos-5 step 10
WinMove("Form1","",$win_pos,-$i,$win_pos,$win_pos)
sleep(10)
Next
EndIf
_WinAPI_TrackMouseEvent($form1,$TME_HOVER)
EndFunc
回复 2# tryhi
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GuiConstantsEx.au3>
Global $is_tracking = False
Global $iteration = 1
Global $sTrackMouseEvent = DllStructCreate('dword;dword;hwnd;dword')
Global $sTME_size = DllStructGetSize($sTrackMouseEvent)
Global $form1=GUICreate('Form1',400,500,-1,0,$WS_POPUP,BitOR($WS_EX_TOPMOST,$WS_EX_TOOLWINDOW))
$button=GUICtrlCreateButton("test",100,100)
DllStructSetData($sTrackMouseEvent, 1, $sTME_size)
DllStructSetData($sTrackMouseEvent, 2, 0x00000002)
DllStructSetData($sTrackMouseEvent, 3, $form1)
DllStructSetData($sTrackMouseEvent, 4, 0xFFFFFFFF)
Global $sTME_POINTER = DllStructGetPtr($sTrackMouseEvent)
GUISetState()
GUIRegisterMsg(0x0200, 'WM_MOUSEMOVE')
GUIRegisterMsg(0x02A3, '__wm_mouseleave')
While GUIGetMsg() <> -3
WEnd
Func WM_MOUSEMOVE($hWndGUI, $MsgID, $wParam, $lParam)
If Not $is_tracking Then
$is_tracking = True
local $win_pos=WinGetPos("Form1")
DllCall('user32.dll', 'bool', 'TrackMouseEvent', 'ptr', $sTME_POINTER) ; We're calling the tracking function
ConsoleWrite('Starting tracking...' &$win_pos& @CRLF)
for $i=$win_pos to $win_pos step 10
ConsoleWrite($win_pos&@CRLF)
if $i>=5 then ExitLoop
WinMove("Form1","",$win_pos,$i,$win_pos,$win_pos)
sleep(10)
Next
ConsoleWrite($i)
EndIf
EndFunc ;==>WM_MOUSEMOVE
Func __wm_mouseleave($hwnd, $msg, $wParam, $lParam)
$is_tracking = False
$iteration += 1
local $win_pos=WinGetPos("Form1")
ConsoleWrite('YOUR MOUSE HAS JUST LEAVED YOUR GUI WINDOW FOR THE ' & $iteration & ' TIME!' &@CRLF)
if$win_pos>=0 then
for $i=$win_pos to $win_pos-5 step 10
ConsoleWrite($win_pos&@CRLF)
WinMove("Form1","",$win_pos,-$i,$win_pos,$win_pos)
sleep(10)
Next
ConsoleWrite($i)
EndIf
EndFunc
试试#include <WindowsConstants.au3>
#include <winapiex.au3>
Global $MOUSELEAVE = 0
$form1 = GUICreate('Form1', 400, 500, -1, 0, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW))
GUICtrlCreateButton("ok", 10, 10)
GUISetState()
GUIRegisterMsg(0x0200, '_WM_MOUSEMOVE')
GUIRegisterMsg(0x02A3, '_WM_MOUSELEAVE')
While GUIGetMsg() <> -3
WEnd
Func _WM_MOUSEMOVE($hWndGUI, $MsgID, $wParam, $lParam)
If $MOUSELEAVE Then Return
Local $win_pos = WinGetPos("Form1")
For $i = $win_pos To $win_pos Step 10
If $i >= 5 Then ExitLoop
WinMove("Form1", "", $win_pos, $i, $win_pos, $win_pos)
Sleep(10)
Next
_WinAPI_TrackMouseEvent($form1, $TME_LEAVE)
$MOUSELEAVE = 1
EndFunc ;==>_WM_MOUSEMOVE
Func _WM_MOUSELEAVE($hWndGUI, $MsgID, $wParam, $lParam)
$MOUSELEAVE = 0
$a = GUIGetCursorInfo($hWndGUI)
If @error Or $a > 0 Then Return
Local $win_pos = WinGetPos("Form1")
If $win_pos >= 0 Then
For $i = $win_pos To $win_pos - 5 Step 10
WinMove("Form1", "", $win_pos, -$i, $win_pos, $win_pos)
Sleep(10)
Next
EndIf
EndFunc ;==>_WM_MOUSELEAVE 本帖最后由 ceoguang 于 2011-3-27 12:50 编辑
#cs
我来解释下楼主的代码进入死循环的原因.
默认情况下,窗口是不会产生WM_MOUSELEAVE消息的.
要接收此消息,必须在光标离开之前通过TrackMouseEvent来激活(RACKMOUSEEVENT结构里dwFlags成员设置为TME_LEAVE,TME_LEAVE = 2)。注:光标移动到控件上也会产生WM_MOUSELEAVE
激活后,一但光标离开窗口WM_MOUSELEAVE消息才会产生.
楼主的代码中,WM_MOUSEMOVE消息产生后激活了WM_MOUSELEAVE,此时WM_MOUSELEAVE消息并未产生.
但上面说到,光标移动到控件上也会产生WM_MOUSELEAVE。
若光标移动到控件,WM_MOUSELEAVE就会被发送到窗口,__wm_mouseleave函数开始工作,函数内又让光标回到窗口并持续移动,移动的过程中WM_MOUSEMOVE就已经工作,移动到最后的时候,光标又到了控件上.
WM_MOUSELEAVE再被发送........
最后附上在楼上代码上修改的消息跟踪代码
#ce
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GuiConstantsEx.au3>
#include <winapi.au3>
Global $is_tracking = False
Global $iteration = 1
Global $sTrackMouseEvent = DllStructCreate('dword;dword;hwnd;dword')
Global $sTME_size = DllStructGetSize($sTrackMouseEvent)
Global $form1 = GUICreate('Form1', 400, 500, -1, 0, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW))
$hCallback = DllCallbackRegister("My_WindowProc", "int", "hWnd;uint;wparam;lparam")
$tCallback = DllCallbackGetPtr($hCallback)
$button = GUICtrlCreateButton("test", 100, 100)
$CallProc = _WinAPI_SetWindowLong(GUICtrlGetHandle(-1), -4, $tCallback)
DllStructSetData($sTrackMouseEvent, 1, $sTME_size)
DllStructSetData($sTrackMouseEvent, 2, 0x00000002)
DllStructSetData($sTrackMouseEvent, 3, $form1)
DllStructSetData($sTrackMouseEvent, 4, 0xFFFFFFFF)
Global $sTME_POINTER = DllStructGetPtr($sTrackMouseEvent)
GUISetState()
GUIRegisterMsg(0x0200, 'WM_MOUSEMOVE')
GUIRegisterMsg(0x02A3, '__wm_mouseleave')
While GUIGetMsg() <> -3
WEnd
GUIDelete()
Func WM_MOUSEMOVE($hWndGUI, $MsgID, $wParam, $lParam)
;If Not $is_tracking Then
; $is_tracking = True
;Local $win_pos = WinGetPos("Form1")
DllCall('user32.dll', 'bool', 'TrackMouseEvent', 'ptr', $sTME_POINTER) ; We're calling the tracking function
;ConsoleWrite('Starting tracking...' & $win_pos & @CRLF)
;For $i = $win_pos To $win_pos Step 10
; ConsoleWrite($win_pos & @CRLF)
; If $i >= 5 Then ExitLoop
; WinMove("Form1", "", $win_pos, $i, $win_pos, $win_pos)
; Sleep(10)
;Next
;ConsoleWrite($i)
;EndIf
Return "GUI_RUNDEFMSG"
EndFunc ;==>WM_MOUSEMOVE
Func __wm_mouseleave($hwnd, $msg, $wParam, $lParam)
;$is_tracking = False
;$iteration += 1
;Local $win_pos = WinGetPos("Form1")
;ConsoleWrite('YOUR MOUSE HAS JUST LEAVED YOUR GUI WINDOW FOR THE ' & $iteration & ' TIME!' & @CRLF)
;If $win_pos >= 0 Then
; For $i = $win_pos To $win_pos - 5 Step 10
; ConsoleWrite($win_pos & @CRLF)
; WinMove("Form1", "", $win_pos, -$i, $win_pos, $win_pos)
; Sleep(10)
; Next
; ConsoleWrite($i)
;EndIf
ConsoleWrite("__wm_mouseleave 0x" & Hex($Msg,6) &@LF)
Return "GUI_RUNDEFMSG"
EndFunc ;==>__wm_mouseleave
Func My_WindowProc($hwnd, $iMsg, $iwParam, $ilParam)
Switch $iMsg
Case 0x200;WM_MOUSEMOVE
Case 0x2A3;WM_MOUSELEAVE
ConsoleWrite("My_WindowProc 0x" & Hex($iMsg,6) &@LF)
Case 0x20;WM_SETCURSOR
EndSwitch
Return _WinAPI_CallWindowProc($CallProc, $hwnd, $iMsg, $iwParam, $ilParam)
EndFunc ;==>My_WindowProc
另外补充一下,WM_MOUSELEAVE消息只会产生一次.要再次使用,必须再次激活.
同样,要检测鼠标停留,也可以用TrackMouseEvent(TRACKMOUSEEVENT结构里的dwFlags成员设置为1,当然也可以是组合,包括:TME_CANCEL,TME_HOVER,TME_LEAVE,TME_NONCLIENT,TME_QUERY.dwHoverTime成员设置为检测时间,单位MS。)来激活WM_MOUSEHOVER.
可以说WM_MOUSELEAVE及WM_MOUSEHOVER是鼠标函数里比较特殊的一对双胞胎。
具体见MSDNhttp://msdn.microsoft.com/en-us/library/ms645604(v=vs.85).aspx 回复 6# ceoguang
也查过MSDN,但总觉得TrackMouseEvent太另类了,用着十分别扭
页:
[1]