fenhanxue 发表于 2018-1-3 20:43:00

$GUI_EVENT_PRIMARYDOWN 对应的消息模式应该怎么写?【已解决】

本帖最后由 fenhanxue 于 2018-1-7 12:01 编辑

问题背景:
创建的GUI取消了标题栏,自己用lable画了一条标题栏
希望鼠标左键按住标题栏(lable),可以自由拖动GUI窗口的位置


不使用消息模式,代码是这样的:#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>

Global $GUI = GUICreate("", 400, 200, -1, -1,$WS_POPUP)
Global $lable_move = GUICtrlCreateLabel("", 0, 0, 370, 30)
GUICtrlSetBkColor(-1, 0x99D9EA)
Global $lable_close = GUICtrlCreateLabel("关闭", 375, 0, 25, 30)

GUISetState(@SW_SHOW)

While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
                Case $lable_close
                        Exit
                Case $GUI_EVENT_PRIMARYDOWN
                        GUI_Move()
        EndSwitch
WEnd



Func GUI_Move()
        ;判断当前鼠标是否在        $lable_move        上方
        Local $temp = GUIGetCursorInfo()
        If $temp = 0 Then Return
        If $temp <> $lable_move Then Return
               
                ;获取鼠标和GUI的相对位置
                Local $GuiPos = WinGetPos($GUI)
                Local $MousePos = MouseGetPos()
                Local $PosDiff
         $PosDiff = $GuiPos - $MousePos
         $PosDiff = $GuiPos - $MousePos


                ;移动GUI
      While _IsPressed("01")
                        Local $MousePos = MouseGetPos()
                        WinMove($GUI, "", $MousePos + $PosDiff, $MousePos + $PosDiff)
                        Sleep(10)
                WEnd
EndFunc上述代码可以正常运行

由于au3是单线程,当程序变复杂后,上述代码将会变得不是非常有效。
例如:
假设GUI里有个BUTTON,按了BUTTON,运行一段func ,假设这个func 会耗时10分钟才会完成, 那么在运行这个func期间,GUI窗口是无法拖动的。必须等func运行完后,才能移动GUI。

所有想改成注册消息的模式,

想请教,这里的$GUI_EVENT_PRIMARYDOWN如何变成消息模式?
我试过下面的代码,但是没有效果:#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>

Global $GUI = GUICreate("", 400, 200, -1, -1,$WS_POPUP)
Global $lable_move = GUICtrlCreateLabel("", 0, 0, 370, 30)
GUICtrlSetBkColor(-1, 0x99D9EA)
Global $lable_close = GUICtrlCreateLabel("关闭", 375, 0, 25, 30)

GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_LBUTTONDOWN, "WM_LBUTTONDOWN")


While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
                Case $lable_close
                        Exit
        EndSwitch
WEnd



Func GUI_Move()
        ;判断当前鼠标是否在        $lable_move        上方
        Local $temp = GUIGetCursorInfo()
        If $temp = 0 Then Return
        If $temp <> $lable_move Then Return
               
                ;获取鼠标和GUI的相对位置
                Local $GuiPos = WinGetPos($GUI)
                Local $MousePos = MouseGetPos()
                Local $PosDiff
         $PosDiff = $GuiPos - $MousePos
         $PosDiff = $GuiPos - $MousePos


                ;移动GUI
      While _IsPressed("01")
                        Local $MousePos = MouseGetPos()
                        WinMove($GUI, "", $MousePos + $PosDiff, $MousePos + $PosDiff)
                        Sleep(10)
                WEnd
EndFunc
       
       
       
Func WM_LBUTTONDOWN($hWndGUI, $MsgID, $WParam, $LParam)
        ConsoleWrite(1)
        GUI_Move()
EndFunc
       

kk_lee69 发表于 2018-1-4 09:39:34

回复 1# fenhanxue

http://www.autoit3.cn/forum.php?mod=viewthread&tid=21578&highlight=WM%5C_LBUTTONDOWN


    Only windows that have the CS_DBLCLKS style can receive WM_LBUTTONDBLCLK messages, which the system generates whenever the user presses, releases, and again presses the left mouse button within the system's double-click time limit. Double-clicking the left mouse button actually generates a sequence of four messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, and WM_LBUTTONUP

kk_lee69 发表于 2018-1-4 10:10:34

回复 1# fenhanxue

http://www.autoit3.cn/thread-25676-1-1.html

kk_lee69 发表于 2018-1-4 10:28:36

回复 1# fenhanxue


#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>




Opt("GUIOnEventMode", 1)

Global $GUI = GUICreate("", 400, 200, -1, -1,$WS_POPUP)
Global $lable_move = GUICtrlCreateLabel("", 0, 0, 370, 30)
GUICtrlSetBkColor(-1, 0x99D9EA)
Global $lable_close = GUICtrlCreateLabel("??", 375, 0, 25, 30)

GUISetState(@SW_SHOW)
GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "GUI_Move")
GUICtrlSetOnEvent($lable_close, "GUI_COMMAND")




While 1

WEnd


       
Func GUI_Move()
      ;判??前鼠?是否在      $lable_move      上方
      Local $temp = GUIGetCursorInfo()
      If $temp = 0 Then Return
      If $temp <> $lable_move Then Return
               
                ;?取鼠?和GUI的相?位置
                Local $GuiPos = WinGetPos($GUI)
                Local $MousePos = MouseGetPos()
                Local $PosDiff
         $PosDiff = $GuiPos - $MousePos
         $PosDiff = $GuiPos - $MousePos


                ;移?GUI
      While _IsPressed("01")
                        Local $MousePos = MouseGetPos()
                        WinMove($GUI, "", $MousePos + $PosDiff, $MousePos + $PosDiff)
                        Sleep(10)
                WEnd
EndFunc
      


Func GUI_COMMAND()
    Switch @GUI_CtrlId

                Case $lable_close
                       Exit
        EndSwitch
EndFunc                
      

fenhanxue 发表于 2018-1-4 11:07:33

本帖最后由 fenhanxue 于 2018-1-4 11:10 编辑

回复 4# kk_lee69


    这样不行呀,KK

如下述代码,当没有触发$bt的时候,窗口是可以自由拖动的
但是,当$bt 触发后,就不能自由拖动了,必须等$bt所对应的函数运行完才行(下例子中的func other())

所以我想弄个注册消息的方式来实现拖动#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>




Opt("GUIOnEventMode", 1)

Global $GUI = GUICreate("", 400, 200, -1, -1,$WS_POPUP)
Global $lable_move = GUICtrlCreateLabel("", 0, 0, 370, 30)
GUICtrlSetBkColor(-1, 0x99D9EA)
Global $lable_close = GUICtrlCreateLabel("??", 375, 0, 25, 30)

GUISetState(@SW_SHOW)
GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "GUI_Move")
GUICtrlSetOnEvent($lable_close, "GUI_COMMAND")

#region我添加的
Global $bt = GUICtrlCreateButton('点我',0,50,400,40)
GUICtrlSetOnEvent($bt, "other")
#endregion

While 1

WEnd


#region我添加的
Func other()
       GUICtrlSetData($bt,'此时你是无法拖动窗口的,但是我想要此时拖动窗口')
       For $i = 1 To 10
               Sleep(1000)
               ConsoleWrite($i)
       Next
       GUICtrlSetData($bt,'点我')
EndFunc
#endregion
      
Func GUI_Move()
      ;判??前鼠?是否在      $lable_move      上方
      Local $temp = GUIGetCursorInfo()
      If $temp = 0 Then Return
      If $temp <> $lable_move Then Return
               
                ;?取鼠?和GUI的相?位置
                Local $GuiPos = WinGetPos($GUI)
                Local $MousePos = MouseGetPos()
                Local $PosDiff
         $PosDiff = $GuiPos - $MousePos
         $PosDiff = $GuiPos - $MousePos


                ;移?GUI
      While _IsPressed("01")
                        Local $MousePos = MouseGetPos()
                        WinMove($GUI, "", $MousePos + $PosDiff, $MousePos + $PosDiff)
                        Sleep(10)
                WEnd
EndFunc
      


Func GUI_COMMAND()
    Switch @GUI_CtrlId

                Case $lable_close
                         Exit
      EndSwitch
EndFunc

kk_lee69 发表于 2018-1-4 11:52:28

回复 5# fenhanxue

我覺得應該不可以吧

依照你的範例事實上不管你用哪種方法 當BT 被執行的時候程式都是 是在長時間忙碌

你也知道AU3 是單線程.........所以 怎麼可能 還有其他的 能力 可以去處理 移動...

標準的 可能可以 移動   那是 因為是WINDOWS 在負責 移動的工作

fenhanxue 发表于 2018-1-4 12:12:57

本帖最后由 fenhanxue 于 2018-1-4 12:15 编辑

回复 6# kk_lee69



    GUIRegisterMsg可以避开单线程的坑的,只是我对系统消息所掌握的水平实在有限,写不出来,看下面例子:
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>




Opt("GUIOnEventMode", 1)

Global $GUI = GUICreate("", 400, 200, -1, -1,$WS_POPUP)
Global $lable_move = GUICtrlCreateLabel("", 0, 0, 370, 30)
GUICtrlSetBkColor(-1, 0x99D9EA)
Global $lable_close = GUICtrlCreateLabel("??", 375, 0, 25, 30)

GUISetState(@SW_SHOW)

GUICtrlSetOnEvent($lable_close, "GUI_COMMAND")

#region我添加的
Global $bt = GUICtrlCreateButton('点我',0,50,400,40)
GUICtrlSetOnEvent($bt, "other")
#endregion

GUIRegisterMsg($WM_LBUTTONDOWN, "WM_LBUTTONDOWN")


While 1

WEnd

Func WM_LBUTTONDOWN($hWndGUI, $MsgID, $WParam, $LParam)
      ConsoleWrite(1)
      GUI_Move()
EndFunc
#region我添加的
Func other()
         GUICtrlSetData($bt,'此时你是无法拖动窗口的,但是我想要此时拖动窗口')
         For $i = 1 To 10
               Sleep(1000)
               ConsoleWrite($i)
         Next
         GUICtrlSetData($bt,'点我')
EndFunc
#endregion
      
Func GUI_Move()
      ;判??前鼠?是否在      $lable_move      上方
      Local $temp = GUIGetCursorInfo()
      If $temp = 0 Then Return
      ;If $temp <> $lable_move Then Return
               
                ;?取鼠?和GUI的相?位置
                Local $GuiPos = WinGetPos($GUI)
                Local $MousePos = MouseGetPos()
                Local $PosDiff
         $PosDiff = $GuiPos - $MousePos
         $PosDiff = $GuiPos - $MousePos


                ;移?GUI
      While _IsPressed("01")
                        Local $MousePos = MouseGetPos()
                        WinMove($GUI, "", $MousePos + $PosDiff, $MousePos + $PosDiff)
                        Sleep(10)
                WEnd
EndFunc
      


Func GUI_COMMAND()
    Switch @GUI_CtrlId

                Case $lable_close
                         Exit
      EndSwitch
EndFunc上面的例子就可以移动。例子的关键是这一行代码:

GUIRegisterMsg($WM_LBUTTONDOWN, "WM_LBUTTONDOWN")

上述代码,我鼠标如果是左键,按住GUI窗口,是可以捕获到消息,并触发函数
WM_LBUTTONDOWN()   的

但是,当我鼠标如果按住的是 $lable_move 这个控件,则捕获不到 $WM_LBUTTONDOWN 消息,也就没法触发函数
WM_LBUTTONDOWN()

所以我想知道问题出在哪里,如何才能捕获到鼠标按住$lable_move控件 的消息

fenhanxue 发表于 2018-1-4 12:22:22

更精简一点的问题是:

鼠标左键按下(非放开。down   非 up)$lable_move 所对应的Windows消息ID是什么

kk_lee69 发表于 2018-1-4 13:26:05

回复 8# fenhanxue

沒時間測試

你的情況 跟我之前遇到一個類似

重點是 你無法 真正抓到 滑鼠 按下的那個觸發點

下面 可以可是標題 不可以

標題其實是因為 圖片 卡住了

放在圖片   其他 功能循環時候 又不行

所以 癥結點 在於 抓到滑鼠 按下的瞬間

可能要使用 回CALL 的方法
參考一下 下面的 用法

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIShellEx.au3>
#include <GuiListView.au3>

Opt( "MustDeclareVars", 1 )

Global $idListView, $idAddSingleSel, $idDelSingleSel

Example()

Func Example()
; Create GUI
GUICreate( "ctrl+single-click --> single-click", 420, 200 )

; Create ListView
$idListView = GUICtrlCreateListView( "", 10, 10, 400, 180, $GUI_SS_DEFAULT_LISTVIEW-$LVS_SINGLESEL, $WS_EX_CLIENTEDGE )
_GUICtrlListView_SetExtendedListViewStyle( $idListView, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT )
Local $hListView = GUICtrlGetHandle( $idListView )

; Add columns to ListView
_GUICtrlListView_InsertColumn( $idListView, 0, "Column 1", 94 )
_GUICtrlListView_InsertColumn( $idListView, 1, "Column 2", 94 )
_GUICtrlListView_InsertColumn( $idListView, 2, "Column 3", 94 )
_GUICtrlListView_InsertColumn( $idListView, 3, "Column 4", 94 )

; Fill ListView
Local $iItems = 100
For $i = 0 To $iItems - 1
    GUICtrlCreateListViewItem( $i & "/Column 1|" & $i & "/Column 2|" & $i & "/Column 3|" & $i & "/Column 4", $idListView )
Next

; Subclass ListView to receive keyboard/mouse messages
Local $pListViewFunc = DllCallbackGetPtr( DllCallbackRegister( "ListViewFunc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) )
_WinAPI_SetWindowSubclass( $hListView, $pListViewFunc, 0, 0 ) ; $iSubclassId = 0, $pData = 0

; Add/del single selection
$idAddSingleSel = GUICtrlCreateDummy()
$idDelSingleSel = GUICtrlCreateDummy()
Local $iItem

; Show GUI
GUISetState( @SW_SHOW )

; Message loop
While 1
    Switch GUIGetMsg()
      Case $idAddSingleSel
      $iItem = GUICtrlRead( $idAddSingleSel )
      _GUICtrlListView_SetItemSelected( $idListView, $iItem, True )
      _GUICtrlListView_SetItemFocused( $idListView, $iItem )
      Case $idDelSingleSel
      $iItem = GUICtrlRead( $idDelSingleSel )
      _GUICtrlListView_SetItemSelected( $idListView, $iItem, False )
      _GUICtrlListView_SetItemFocused( $idListView, $iItem )
      Case $GUI_EVENT_CLOSE
      ExitLoop
    EndSwitch
WEnd

; Cleanup
_WinAPI_RemoveWindowSubclass( $hListView, $pListViewFunc, 0 )
GUIDelete()
EndFunc

Func ListViewFunc( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData )
If $iMsg <> $WM_LBUTTONDOWN Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )

Switch $wParam
    Case 0x0001; 0x0001 = MK_LBUTTON (LButton down)
      If _GUICtrlListView_GetSelectedCount( $idListView ) Then
      Local $aHit = _GUICtrlListView_HitTest( GUICtrlGetHandle( $idListView ), BitAND( $lParam, 0xFFFF ), BitShift( $lParam, 16 ) )
      If Not ( @error Or $aHit = -1 ) Then
          If _GUICtrlListView_GetItemSelected( $idListView, $aHit ) Then
            GUICtrlSendToDummy( $idDelSingleSel, $aHit )
          Else
            GUICtrlSendToDummy( $idAddSingleSel, $aHit )
          EndIf
      EndIf
      Return 0 ; Disable single-click in ListView to prevent resetting selections
      EndIf

    Case 0x0009; 0x0009 = MK_LBUTTON (LButton down) + MK_CONTROL (Ctrl down)
      Return 0   ; Disable single selections in ListView with ctrl+single-click
EndSwitch

Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )
; Call next function in subclass chain (this forwards messages to main GUI)
#forceref $iSubclassId, $pData
EndFunc


上面範例 要看的是 滑鼠 攔截消息的方法

kk_lee69 发表于 2018-1-4 14:21:19

回复 8# fenhanxue

解決了

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>

Opt("GUIOnEventMode", 1)

Global $GUI = GUICreate("", 400, 200, -1, -1,$WS_POPUP)
Global $lable_move = GUICtrlCreateLabel("", 0, 0, 370, 30)
GUICtrlSetBkColor(-1, 0x99D9EA)
Global $lable_close = GUICtrlCreateLabel("??", 375, 0, 25, 30)

GUISetState(@SW_SHOW)

GUICtrlSetOnEvent($lable_close, "GUI_COMMAND")
GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")

#region我添加的
Global $bt = GUICtrlCreateButton('?我',0,50,400,40)
GUICtrlSetOnEvent($bt, "other")
#endregion

GUIRegisterMsg($WM_LBUTTONDOWN, "WM_LBUTTONDOWN")



While 1

WEnd

Func WM_LBUTTONDOWN($hWndGUI, $MsgID, $WParam, $LParam)
      ConsoleWrite(999)
      GUI_Move()
EndFunc
#region我添加的
Func other()
         GUICtrlSetData($bt,'此?你是?法拖?窗口的,但是我想要此?拖?窗口')
         For $i = 1 To 10
               Sleep(1000)
               ConsoleWrite($i)
         Next
         GUICtrlSetData($bt,'?我')
EndFunc
#endregion
      
Func GUI_Move()
      ;判??前鼠?是否在      $lable_move      上方
      Local $temp = GUIGetCursorInfo()
      If $temp = 0 Then Return
      ;If $temp <> $lable_move Then Return
               
                ;?取鼠?和GUI的相?位置
                Local $GuiPos = WinGetPos($GUI)
                Local $MousePos = MouseGetPos()
                Local $PosDiff
         $PosDiff = $GuiPos - $MousePos
         $PosDiff = $GuiPos - $MousePos


                ;移?GUI
      While _IsPressed("01")
                        Local $MousePos = MouseGetPos()
                        WinMove($GUI, "", $MousePos + $PosDiff, $MousePos + $PosDiff)
                        Sleep(10)
                WEnd
EndFunc
      


Func GUI_COMMAND()
    Switch @GUI_CtrlId

                Case $lable_close
                        Exit
                                               
                                               
                                Case $lable_move
                                               GUI_Move()
      EndSwitch
EndFunc

Func MY_WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
    Local $nNotifyCode = BitShift($wParam, 16)
    Local $nID = BitAND($wParam, 0x0000FFFF)
    Local $hCtrl = $lParam
       
        Switch $nID
                CASE $lable_move
                GUI_Move()
        EndSwitch       

    Return $GUI_RUNDEFMSG
EndFunc

fenhanxue 发表于 2018-1-4 17:16:41

回复 10# kk_lee69


    谢谢KK,

奇怪的是为什么$WM_LBUTTONDOWN 消息在控件上无法捕获

kk_lee69 发表于 2018-1-4 17:20:09

回复 11# fenhanxue

其實 AU3 還是單線程   當你移動時迴圈也就停止了...
所以 只是 誰先跑 誰後跑.....

至於 WM_LBUTTONDOWN我也不知道    但是之前就有發現.....
页: [1]
查看完整版本: $GUI_EVENT_PRIMARYDOWN 对应的消息模式应该怎么写?【已解决】