找回密码
 加入
搜索
查看: 3890|回复: 6

[GUI管理] WM_MOUSELEAVE消息问题[已解决]

  [复制链接]
发表于 2011-3-26 16:19:28 | 显示全部楼层 |阅读模式
本帖最后由 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[1] to $win_pos[3] step 10
                        if $i>=5 then ExitLoop
                        WinMove("Form1","",$win_pos[0],$i,$win_pos[2],$win_pos[3])
                        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[1]>=0 then 
                for $i=$win_pos[1] to $win_pos[3]-5 step 10
                        WinMove("Form1","",$win_pos[0],-$i,$win_pos[2],$win_pos[3])
                        sleep(10)
                Next
        EndIf
        _WinAPI_TrackMouseEvent($form1,$TME_HOVER)
EndFunc
发表于 2011-3-26 19:35:54 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
 楼主| 发表于 2011-3-26 20:20:41 | 显示全部楼层
回复 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[1]& @CRLF)
                for $i=$win_pos[1] to $win_pos[3] step 10
                        ConsoleWrite($win_pos[1]&@CRLF)
                        if $i>=5 then ExitLoop
                        WinMove("Form1","",$win_pos[0],$i,$win_pos[2],$win_pos[3])
                        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[1]>=0 then 
                for $i=$win_pos[1] to $win_pos[3]-5 step 10
                        ConsoleWrite($win_pos[1]&@CRLF)
                        WinMove("Form1","",$win_pos[0],-$i,$win_pos[2],$win_pos[3])
                        sleep(10)
                Next
                ConsoleWrite($i)
        EndIf
EndFunc
发表于 2011-3-26 23:54:54 | 显示全部楼层
试试
#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[1] To $win_pos[3] Step 10
                If $i >= 5 Then ExitLoop
                WinMove("Form1", "", $win_pos[0], $i, $win_pos[2], $win_pos[3])
                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[4] > 0 Then Return
        Local $win_pos = WinGetPos("Form1")
        If $win_pos[1] >= 0 Then
                For $i = $win_pos[1] To $win_pos[3] - 5 Step 10
                        WinMove("Form1", "", $win_pos[0], -$i, $win_pos[2], $win_pos[3])
                        Sleep(10)
                Next
        EndIf
EndFunc   ;==>_WM_MOUSELEAVE

评分

参与人数 1金钱 +50 贡献 +5 收起 理由
3mile + 50 + 5 多谢关注

查看全部评分

发表于 2011-3-27 11:49:32 | 显示全部楼层
本帖最后由 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[1] & @CRLF)
                ;For $i = $win_pos[1] To $win_pos[3] Step 10
                ;        ConsoleWrite($win_pos[1] & @CRLF)
                ;        If $i >= 5 Then ExitLoop
                ;        WinMove("Form1", "", $win_pos[0], $i, $win_pos[2], $win_pos[3])
                ;        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[1] >= 0 Then
        ;        For $i = $win_pos[1] To $win_pos[3] - 5 Step 10
        ;                ConsoleWrite($win_pos[1] & @CRLF)
        ;                WinMove("Form1", "", $win_pos[0], -$i, $win_pos[2], $win_pos[3])
        ;                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

评分

参与人数 1金钱 +30 收起 理由
3mile + 30 学习了

查看全部评分

发表于 2011-3-27 12:03:36 | 显示全部楼层
另外补充一下,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
 楼主| 发表于 2011-3-27 12:50:33 | 显示全部楼层
回复 6# ceoguang
也查过MSDN,但总觉得TrackMouseEvent太另类了,用着十分别扭
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-6-11 19:45 , Processed in 0.087362 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表