Jump to content

Resizable & Dragable Windows Controls


MattyD
 Share

Recommended Posts

Link to comment
Share on other sites

Very nice !
Do you guys can reproduce this :
1) Launch OP's script and drag button 2 over button 1 (first pic below) then drop (release mouse click)
2) Drag button 1 to the right (2nd pic) ...
3) ... then drop (3rd pic)

Temporaryartefact.png.5a0440e0e5d205e5f7a9e488c3bf31d9.png

I think we discussed this a couple of years ago (I'll try to find where) and there was a solution, maybe a style to add, can't remember.

Edited by pixelsearch
typo
Link to comment
Share on other sites

yep got it.  Here a way to solve it :

Case $WM_SETCURSOR
      $iSrc = BitAND($lParam, 0xFFFF)
      $iEvent = BitShift($lParam, 16)
      If $iSrc = $HTCAPTION And $iEvent = $WM_LBUTTONDOWN Then
         _WinAPI_RedrawWindow($hWnd, 0, 0, $RDW_INVALIDATE + $RDW_FRAME)
         $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEALL)
        _WinAPI_SetCursor($hCursor)
        Return True
      EndIf

ps.  it is not working all the times...

pps. seems that solves the issue (changed code above)

_WinAPI_RedrawWindow($hWnd, 0, 0, $RDW_INVALIDATE + $RDW_FRAME)

 

Edited by Nine
Link to comment
Share on other sites

@Nine yes, Redraw did it. This is the part I just found in a personal script which uses Redraw too :

; Move the control until the mouse left button is released
Do
    Sleep(10)
    $cInfo = GUIGetCursorInfo($hGui)
    ControlMove($hGui, "", $iControl, $cInfo[0] - $iSubtractX, $cInfo[1] - $iSubtractY)

    ; _WinAPI_RedrawWindow($hControl)
    DllCall($hDll, "bool", "RedrawWindow", "hwnd", $hControl, "struct*", 0, "handle", 0, "uint", 5)

Until Not $cInfo[2]
Edited by pixelsearch
typo
Link to comment
Share on other sites

Hope this script will work for you as it works for me, no callback, no subclassing, no redraw, no nothing :D
Both buttons seem to be draggable fluently, fingers crossed.

#include <GUIConstantsEx.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration

Global $g_hGui

Example()

;==============================================
Func Example()

    Local $idBtn, $idBtn2, $aInfo

    $g_hGui = GUICreate("Drag Buttons", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW)
    $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80, $WS_CLIPSIBLINGS)
    $idBtn2 = GUICtrlCreateButton("Button 2", 90, 4, 80, 80, $WS_CLIPSIBLINGS)

    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                Exit

            Case $GUI_EVENT_PRIMARYDOWN
                $aInfo = GUIGetCursorInfo($g_hGui)
                If (Not @error) And ($aInfo[4] = $idBtn Or $aInfo[4] = $idBtn2) Then
                    _WinAPI_SetWindowPos(GUICtrlGetHandle($aInfo[4]), $HWND_TOP , 0, 0, 0, 0, $SWP_NOMOVE + $SWP_NOSIZE)
                    _ControlMove()
                EndIf
        EndSwitch
    WEnd

EndFunc   ;==>Example

;==============================================
Func _ControlMove()

    Local $aInfo, $idControl, $hControl, $aPos, $iSubtractX, $iSubtractY

    $aInfo = GUIGetCursorInfo($g_hGui)
    $idControl = $aInfo[4] ; +++
    $hControl = GUICtrlGetHandle($idControl)
    $aPos = ControlGetPos($g_hGui, "", $idControl)
    $iSubtractX = $aInfo[0] - $aPos[0]
    $iSubtractY = $aInfo[1] - $aPos[1]

    Do
        $aInfo = GUIGetCursorInfo($g_hGui)
        ; ConsoleWrite($aInfo[4] & @crlf) ; varies from 3 => 4 => 3 => 4 ... while dragging

        ; https://www.autoitscript.com/forum/topic/211959-drag-and-drop-items-labels-vertically-among-themselves/?do=findComment&comment=1534654
        ; ControlMove($g_hGui, "", $idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY) ; issue on Minimize
        
        GUICtrlSetPos($idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY)

        _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0, $SWP_NOMOVE + $SWP_NOSIZE)        
        Sleep(10)
    Until Not $aInfo[2]

EndFunc   ;==>_ControlMove

 

Edited by pixelsearch
typo
Link to comment
Share on other sites

Link to comment
Share on other sites

21 minutes ago, Nine said:

I need to remember where I saw that before. 

It was me. :) déjà vu


Edit:

Func _ControlMove()

    Local $aInfo, $idControl, $hControl, $aPos, $iSubtractX, $iSubtractY

    $aInfo = GUIGetCursorInfo($g_hGui)
    $idControl = $aInfo[4] ; +++
    $hControl = GUICtrlGetHandle($idControl)
    $aPos = ControlGetPos($g_hGui, "", $idControl)
    $iSubtractX = $aInfo[0] - $aPos[0]
    $iSubtractY = $aInfo[1] - $aPos[1]

    Do
        $aInfo = GUIGetCursorInfo($g_hGui)
        ControlMove($g_hGui, "", $idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY)
        _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0, $SWP_NOMOVE + $SWP_NOSIZE)
        Sleep(10)
    Until Not $aInfo[2]

    GUICtrlSetPos($idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY)

EndFunc   ;==>_ControlMove

 

Edited by ioa747

I know that I know nothing

Link to comment
Share on other sites

@Nine yes I noted that inconvenience before I posted the script, but as it did same in OP's script...

Another thing I noticed while scripting : if you add a ConsoleWrite inside the Do... Until loop :

Do
    $aInfo = GUIGetCursorInfo($g_hGui)
    ConsoleWrite($aInfo[4] & @crlf) ; varies from 3 => 4 => 3 => 4 ... while dragging
    ControlMove($g_hGui, "", $idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY)      
    _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0, $SWP_NOMOVE + $SWP_NOSIZE)
    Sleep(10)
Until Not $aInfo[2]

...then the Console display varies constantly from 3 to 4 while dragging (depending on the moment the controls overlap or not). That's why I had to ControlMove $idControl and not $aInfo[4]. It drove me nuts during the scripting phase, as I wanted to get rid of $idControl in the function (just to use $aInfo[4] everywhere) but the GUI display goes wrong when you try to ControlMove $aInfo[4]

Concerning the Minimize / Restore inconvenience in both our scripts, I hope there will be a way to solve it.

Edited by pixelsearch
typo
Link to comment
Share on other sites

I just added a $WS_OVERLAPPEDWINDOW style to the GUI (to test Maximize and Resize)

$g_hGui = GUICreate("Drag Buttons", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW)
    
; https://www.autoitscript.com/trac/autoit/ticket/3877 : 
; apply $WS_CLIPSIBLINGS style to both button controls (or $WS_EX_COMPOSITED as GUI extended style, as also suggested in Ticket 3877 ?)
; But $WS_EX_COMPOSITED worked fine until Win7 included, not sure it's 100% reliable on OS's >= Win8

$idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80, $WS_CLIPSIBLINGS)
$idBtn2 = GUICtrlCreateButton("Button 2", 90, 4, 80, 80, $WS_CLIPSIBLINGS)

Please note how the GUI display goes wrong without the $WS_CLIPSIBLINGS style for both buttons, as discussed in Trac ticket 3877, which made @jpm add this sentence to AutoIt help file 3.3.16.1, topic GUICtrlCreateLabel

If you really need to create a label that overlap other control you can set the style to $WS_CLIPSIBLINGS. In fact that has a little performance drawback [...]
Edited by pixelsearch
Link to comment
Share on other sites

@pixelsearch   I teased it a little. :)

Spoiler
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPISysWin.au3>
#include <StaticConstants.au3>

Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration

Example()

;==============================================
Func Example()

    Local $hGui, $idBtn, $idBtn2, $hLbl, $aInfo

    $hGui = GUICreate("Drag Buttons", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW)
    $idBtn = GUICtrlCreateButton("Button 1", 4, 30, 80, 80, $WS_CLIPSIBLINGS)
    $idBtn2 = GUICtrlCreateButton("Button 2", 90, 30, 80, 80, $WS_CLIPSIBLINGS)
    $hLbl = GUICtrlCreateLabel("Label Test", 94, 4, 80, 15, BitOR($SS_CENTER, $WS_CLIPSIBLINGS))

    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                Exit

            Case $GUI_EVENT_PRIMARYDOWN
                $aInfo = GUIGetCursorInfo($hGui)
                If (Not @error) And ($aInfo[4] = $idBtn Or $aInfo[4] = $idBtn2 Or $aInfo[4] = $hLbl) Then
                    _ControlMove($hGui)
                EndIf
        EndSwitch
    WEnd

EndFunc   ;==>Example

Func _ControlMove($hGui)

    If Not WinActive($hGui) Then Return
    Local $aInfo = GUIGetCursorInfo($hGui)

    Local $idControl = $aInfo[4]
    If $aInfo[4] = 0 Then Return ; Return if not control

    Local $aPos = ControlGetPos($hGui, "", $idControl)
    Local $iSubtractX = $aInfo[0] - $aPos[0]
    Local $iSubtractY = $aInfo[1] - $aPos[1]
    Local $iCursorId = MouseGetCursor()
    GUISetCursor(0, 1, $hGui)

    _WinAPI_SetWindowPos(GUICtrlGetHandle($idControl), $HWND_TOP, 0, 0, 0, 0, $SWP_NOMOVE + $SWP_NOSIZE)

    Local $aInfoNew = $aInfo

    Do
        $aInfo = GUIGetCursorInfo($hGui)
        If $aInfoNew[0] <> $aInfo[0] Or $aInfoNew[1] <> $aInfo[1] Then
            $aInfoNew = $aInfo
            GUICtrlSetPos($idControl, $aInfoNew[0] - $iSubtractX, $aInfoNew[1] - $iSubtractY)
        EndIf
        Sleep(10)
    Until Not $aInfo[2]

    GUISetCursor($iCursorId, 0, $hGui)

EndFunc   ;==>_ControlMove

 

Edit:
added GUISetCursor effect
I added the Nine 's instructions, from below.

 

Edited by ioa747
update

I know that I know nothing

Link to comment
Share on other sites

7 minutes ago, pixelsearch said:

even if you add the $WS_EX_COMPOSITED Gui extended style ?

It is better.  But it flickers quite a bit when moving slowly.  This makes it very tolerable :

While $aInfo[2]
    $aInfoNew = GUIGetCursorInfo($g_hGui)
    If $aInfoNew[0] <> $aInfo[0] Or $aInfoNew[1] <> $aInfo[1] Then
      GUICtrlSetPos($idControl, $aInfoNew[0] - $iSubtractX, $aInfoNew[1] - $iSubtractY)
      $aInfo = $aInfoNew
    EndIf
  WEnd

 

Link to comment
Share on other sites

At least we have now a few solutions : $WS_EX_COMPOSITED, $WS_CLIPSIBLINGS, your last code (Nine), also the fact that we won't need a resizable GUI in all cases etc...

I guess if a user is interested in moving all controls inside a GUI for a display that suits him, then all controls coords and GUI coords (if resizable) should be saved before exiting the script (maybe in an ini file)

When the script is run again, then :
* If there is an associated ini file : use all coords for GUI & controls from the ini file.
* If there isn't an associated ini file : use hard-coded default GUI & controls coords

It should be easy to add a local variable $bMovingPhase to allow (or not) the controls moving phase. This variable should be present in all Case of main loop and could have its value modified through a checkbox control (as OP did), a menu option, a HotKey etc...

We need it in all Case of main loop because when Case $GUI_EVENT_PRIMARYDOWN ends, then Case $idBtn2 is always triggered (if the user dragged & drop Button 2)
 

Case $GUI_EVENT_PRIMARYDOWN
    If $bMovingPhase Then ; allow to move all controls when the variable is True
        ...
    EndIf

Case $idBtn
    If $bMovingPhase Then ContinueLoop
    ConsoleWrite("Button 1 code" & @crlf)

Case $idBtn2
    If $bMovingPhase Then ContinueLoop
    ConsoleWrite("Button 2 code" & @crlf)

Interesting thread indeed :)

Edited by pixelsearch
typo
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...