Jump to content
Herb191

How to resize a shape WHILE resizing a GUI

Recommended Posts

Herb191

I am working on a script that draws a shape around a control. Right now it works but it does not update at the same time as the other controls in the GUI.  Does anyone know of a way that I can modify it to resize at the same time?

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

Opt("GuiOnEventMode", 1)
Opt("MustDeclareVars", 1)

Global $g_hGUI, $g_idDummy

$g_hGUI = GUICreate("", 500, 500, -1, -1, $WS_SIZEBOX + $WS_MAXIMIZEBOX, $WS_EX_COMPOSITED)

$g_idDummy = GUICtrlCreateButton("", 250, 250, 50, 50)
GUICtrlSetResizing($g_idDummy, $GUI_DOCKAUTO)

GUISetState()

GUISetOnEvent($GUI_EVENT_CLOSE, "WinEvents", $g_hGUI)

; redraws on resize but only after mouse is released
GUISetOnEvent($GUI_EVENT_RESIZED, "ReDraw", $g_hGUI)

DrawSelector("Selector", $g_idDummy)

While 1
    Sleep(250)
WEnd

Func ReDraw()
    DrawSelector("Selector", $g_idDummy)
EndFunc   ;==>ReDraw

Func DrawSelector($sSelectorTitle, $idControl)
    Local $hBitmap, $hGui, $hGraphic, $GuiSizeX = @DesktopWidth, $GuiSizeY = @DesktopHeight
    Local $GuiSize = 70, $hWnd, $hDC, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend, $hPen
    Local $iOpacity = 255, $aPos

    If WinExists($sSelectorTitle, "") Then GUIDelete(WinGetHandle($sSelectorTitle))

    $aPos = ControlRelativeToDesktop($g_hGUI, $idControl)

    $hGui = GUICreate($sSelectorTitle, $GuiSizeX, $GuiSizeY, -1, -1, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
    GUISetState()

    _GDIPlus_Startup()
    $hWnd = _WinAPI_GetDC($g_hGUI)
    $hDC = _WinAPI_CreateCompatibleDC($hWnd)
    $hBitmap = _WinAPI_CreateCompatibleBitmap($hWnd, $GuiSizeX, $GuiSizeY)
    _WinAPI_SelectObject($hDC, $hBitmap)
    $hGraphic = _GDIPlus_GraphicsCreateFromHDC($hDC)

    $hPen = _GDIPlus_PenCreate(0xFFFF0000, 5)

    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $GuiSizeX)
    DllStructSetData($tSize, "Y", $GuiSizeY)
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)

    _GDIPlus_GraphicsDrawRect($hGraphic, $aPos[0], $aPos[1], $aPos[2], $aPos[3], $hPen) ; <-- Graphics to layered wimdow.
    _WinAPI_UpdateLayeredWindow($hGui, $hWnd, 0, $pSize, $hDC, $pSource, 0, $pBlend, $ULW_ALPHA)

    _GDIPlus_PenDispose($hPen)
    _GDIPlus_GraphicsDispose($hGraphic)
    _WinAPI_ReleaseDC(0, $hWnd)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hDC)
    _GDIPlus_Shutdown()
EndFunc   ;==>DrawSelector

Func ControlRelativeToDesktop($hWnd, $idControl)
    Local $Point, $aControlXYPos

    Dim $aPos[4]

    $aControlXYPos = ControlGetPos($hWnd, "", $idControl)

    $Point = DllStructCreate("int;int")
    DllStructSetData($Point, 1, $aControlXYPos[0])
    DllStructSetData($Point, 2, $aControlXYPos[1])
    DllCall("User32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "ptr", DllStructGetPtr($Point))

    ;x
    $aPos[0] = DllStructGetData($Point, 1)

    ;y
    $aPos[1] = DllStructGetData($Point, 2)

    ;width
    $aPos[2] = $aControlXYPos[2]

    ;height
    $aPos[3] = $aControlXYPos[3]

    Return $aPos
EndFunc   ;==>ControlRelativeToDesktop

Func WinEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            Exit
    EndSelect
EndFunc   ;==>WinEvents

 

Share this post


Link to post
Share on other sites
Herb191

I would be appreciative of any help. I wouldn't ask if I wasn't stuck.

Share this post


Link to post
Share on other sites
Herb191

I got it working after messing with it for a few days. It still has an annoying flash but it works. Here is the code for anyone that might be interested.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>

Opt("GuiOnEventMode", 1)
Opt("MustDeclareVars", 1)

Global $g_hGUI, $g_idDummy, $g_hChildGui

$g_hGUI = GUICreate("", 500, 500, -1, -1, $WS_SIZEBOX + $WS_MAXIMIZEBOX, $WS_EX_COMPOSITED)

$g_idDummy = GUICtrlCreateButton("", 250, 250, 50, 50)
GUICtrlSetResizing($g_idDummy, $GUI_DOCKAUTO)

GUISetState()

GUISetOnEvent($GUI_EVENT_CLOSE, "WinEvents", $g_hGUI)

GUISetOnEvent($GUI_EVENT_RESIZED, "UpdateSelector", $g_hGUI)
GUIRegisterMsg($WM_SIZE, "UpdateSelector")
DrawSelector("Selector", $g_idDummy)

While 1
    Sleep(250)
WEnd

Func DrawSelector($sSelectorTitle, $idControl)
    Local $hBitmap, $hGraphic, $aMainGUIPos, $GuiSize = 70, $hWnd, $hDC, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend, $hPen
    Local $iOpacity = 255, $aControlPos

    If WinExists($sSelectorTitle, "") Then
        GUIDelete(WinGetHandle($sSelectorTitle, ""))
    EndIf

    $aControlPos = ControlGetPos($g_hGUI, "", $idControl)

    $aMainGUIPos = WinGetClientSize($g_hGUI)

    $g_hChildGui = GUICreate($sSelectorTitle, $aControlPos[0], $aControlPos[1], 0, 0, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))

    DllCall("user32.dll", "int", "SetParent", "hwnd", $g_hChildGui, "hwnd", $g_hGUI)

    _GDIPlus_Startup()
    $hWnd = _WinAPI_GetDC($g_hGUI)
    $hDC = _WinAPI_CreateCompatibleDC($hWnd)
    $hBitmap = _WinAPI_CreateCompatibleBitmap($hWnd, $aMainGUIPos[0], $aMainGUIPos[1])
    _WinAPI_SelectObject($hDC, $hBitmap)
    $hGraphic = _GDIPlus_GraphicsCreateFromHDC($hDC)

    $hPen = _GDIPlus_PenCreate(0xFFFF0000, 5)

    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $aMainGUIPos[0])
    DllStructSetData($tSize, "Y", $aMainGUIPos[1])
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)

    _GDIPlus_GraphicsDrawRect($hGraphic, $aControlPos[0], $aControlPos[1], $aControlPos[2], $aControlPos[3], $hPen)
    _WinAPI_UpdateLayeredWindow($g_hChildGui, $hWnd, 0, $pSize, $hDC, $pSource, 0, $pBlend, $ULW_ALPHA)

    GUISetState(@SW_SHOW, $g_hChildGui)

    _GDIPlus_PenDispose($hPen)
    _GDIPlus_GraphicsDispose($hGraphic)
    _WinAPI_ReleaseDC(0, $hWnd)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hDC)
    _GDIPlus_Shutdown()
EndFunc   ;==>DrawSelector

Func UpdateSelector($hWnd, $iMsg, $wparam, $lparam)
    WinMove($g_hChildGui,"",-1000,-1000)

    DrawSelector("Selector", $g_idDummy)
EndFunc

Func WinEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            Exit
    EndSelect
EndFunc   ;==>WinEvents

 

Share this post


Link to post
Share on other sites
argumentum

I got it working after messing with it for a few days. It still has an annoying flash but it works. Here is the code for anyone that might be interested.

​is not working for me. Maybe in the paste to the post something got lost ?

Share this post


Link to post
Share on other sites
Herb191

​is not working for me. Maybe in the paste to the post something got lost ?

​Interesting. I just copied the code from the forum and it worked for me. What do you mean when you say its "not working"?

Share this post


Link to post
Share on other sites
Herb191

Darn. I just tested it on another computer and had the same problem. I have been going at it all day. I will try to fix it tomorrow. Unless anyone knows why its not working. :whistle:

Share this post


Link to post
Share on other sites
argumentum

this is not the approach you are looking for but I have no idea what you want it for so hidden bellow, mostly out of shame

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#Region ### START Koda GUI section ### Form=
Local $Form1 = GUICreate("Form1", 200, 100, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX, $WS_THICKFRAME, $WS_TABSTOP))
Local $Button1 = GUICtrlCreateButton_wBox(4, "Button1", 20, 20, 50, 50)
Local $Button2 = GUICtrlCreateButton_wBox(4, "Button2", 40, 60, 100, 25)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

Func GUICtrlCreateButton_wBox($sBoxSize, $sText, $iLeft, $iTop, $iWidth, $iHeight, $iStyle = -1, $iExStyle = -1)
    Local $iCtrl = GUICtrlCreateButton($sText, $iLeft, $iTop, $iWidth, $iHeight, $iStyle, $iExStyle)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)
    GUICtrlCreateLabel("", $iLeft - $sBoxSize, $iTop - $sBoxSize, $sBoxSize, $iHeight + $sBoxSize + $sBoxSize, $iStyle, $iExStyle)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)
    GUICtrlCreateLabel("", $iLeft - $sBoxSize, $iTop - $sBoxSize, $sBoxSize + $sBoxSize + $iWidth, $sBoxSize, $iStyle, $iExStyle)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)
    GUICtrlCreateLabel("", $iLeft - $sBoxSize, $iTop + $iHeight, $sBoxSize + $sBoxSize + $iWidth, $sBoxSize, $iStyle, $iExStyle)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)
    GUICtrlCreateLabel("", $iLeft + $iWidth, $iTop - $sBoxSize , $sBoxSize, $iHeight + $sBoxSize + $sBoxSize, $iStyle, $iExStyle)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)
    Return $iCtrl
EndFunc   ;==>GUICtrlCreateButton_wBox

Func GUICtrlButton_wBox_Color($iCtrl, $iColor)
    For $n = $iCtrl + 1 To $iCtrl + 4
        GUICtrlSetBkColor($n, $iColor)
    Next
EndFunc   ;==>GUICtrlButton_wBox_Color

Local $sec = @SEC
Local $toBeOrNot = True
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            GUIDelete()
            ExitLoop
        Case $Button1
            ConsoleWrite("$Button1" & @CRLF)
    EndSwitch
    If $sec = @SEC Then ContinueLoop
    $sec = @SEC
    $toBeOrNot = Not $toBeOrNot
    If $toBeOrNot Then
        GUICtrlButton_wBox_Color($Button1, 0xFF0000)
        GUICtrlButton_wBox_Color($Button2, 0x00FFFF)
    Else
        GUICtrlButton_wBox_Color($Button2, 0xFF00FF)
        GUICtrlButton_wBox_Color($Button1, 0x0000FF)
    EndIf
WEnd

 

is my take :) 

Share this post


Link to post
Share on other sites
Herb191

Thanks @argumentum for taking a shot at it. Unfortunately I need to just show a border around a control because most of the time the control will actually be hidden.

Anyway, I came up with this. I was hoping to avoid splitting it into more then one script but I don't see a way around it for what I need.

Example GUI

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

Opt("GuiOnEventMode", 1)
Opt("MustDeclareVars", 1)

Global $g_hGUI, $g_idDummy

$g_hGUI = GUICreate("test", 500, 500, -1, -1, $WS_SIZEBOX + $WS_MAXIMIZEBOX, $WS_EX_COMPOSITED)

$g_idDummy = GUICtrlCreateButton("", 250, 250, 50, 50)
GUICtrlSetResizing($g_idDummy, $GUI_DOCKAUTO)

GUISetState()

GUISetOnEvent($GUI_EVENT_CLOSE, "WinEvents", $g_hGUI)

SelectControl($g_hGUI, "[INSTANCE:1]", 5, "0xFF0000")

While 1
    Sleep(250)
WEnd

Func SelectControl($hGUI, $idControl, $iBorderWidth, $iBorderColor)
    Run(@ScriptDir & "\Selector.exe " & $hGUI & " " & $idControl & " " & $iBorderWidth & " " & $iBorderColor)
EndFunc   ;==>SelectControl

Func WinEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            Exit
    EndSelect
EndFunc   ;==>WinEvents

 

Selector script (needs to be compiled to work).

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

Opt("TrayIconHide", 1)
Opt("MustDeclareVars", 1)

;will exit if not ran with all parameters
If $CmdLine[0] <> 4 Then
    Exit
EndIf

Global $g_hSelectorGUI, $g_aMainWinCtrlPos, $g_iBorderWidth, $g_hWinHandle, $g_idControl, $g_iBorderWidth, $g_iBorderColor

$g_hWinHandle = $CmdLine[1]
$g_idControl = $CmdLine[2]
$g_iBorderWidth = $CmdLine[3]
$g_iBorderColor = $CmdLine[4]

Dim $g_aMainWinCtrlPos[4]

$g_hSelectorGUI = GUICreate("Selector", 0, 0, 0, 0, $WS_POPUP, $WS_EX_TOPMOST + $WS_EX_TOOLWINDOW)
GUISetBkColor($g_iBorderColor)

GUISetState(@SW_SHOW, $g_hSelectorGUI)

;updates the selector
AdlibRegister("UpdateSelector")

While 1
    Sleep(250)
WEnd

Func UpdateSelector()
    ;exits if the main program closes
    If Not WinExists($g_hWinHandle) Then Exit

    Local $aPos, $hInner_rgn, $hOuter_rgn

    $aPos = ControlRelativeToDesktop($g_hWinHandle, $g_idControl)

    If $aPos[0] = $g_aMainWinCtrlPos[0] And $aPos[1] = $g_aMainWinCtrlPos[1] And $aPos[2] = $g_aMainWinCtrlPos[2] And $aPos[3] = $g_aMainWinCtrlPos[3] Then Return

    $g_aMainWinCtrlPos = $aPos

    $g_aMainWinCtrlPos = ControlRelativeToDesktop($g_hWinHandle, $g_idControl)
    WinMove($g_hSelectorGUI, "", $g_aMainWinCtrlPos[0] - $g_iBorderWidth, $g_aMainWinCtrlPos[1] - $g_iBorderWidth, $g_aMainWinCtrlPos[2] + $g_iBorderWidth * 2, $g_aMainWinCtrlPos[3] + $g_iBorderWidth * 2)
    $hInner_rgn = _WinAPI_CreateRectRgn($g_aMainWinCtrlPos[0], $g_aMainWinCtrlPos[1], $g_aMainWinCtrlPos[0] + $g_aMainWinCtrlPos[2], $g_aMainWinCtrlPos[1] + $g_aMainWinCtrlPos[3])

    Local $hOuter_rgn, $hInner_rgn, $hCombined_rgn

    $hOuter_rgn = _WinAPI_CreateRectRgn(0, 0, $g_aMainWinCtrlPos[2] + $g_iBorderWidth * 2, $g_aMainWinCtrlPos[3] + $g_iBorderWidth * 2)
    $hInner_rgn = _WinAPI_CreateRectRgn($g_iBorderWidth, $g_iBorderWidth, $g_aMainWinCtrlPos[2] + $g_iBorderWidth, $g_aMainWinCtrlPos[3] + $g_iBorderWidth)

    $hCombined_rgn = _WinAPI_CreateRectRgn(0, 0, 0, 0)
    _WinAPI_CombineRgn($hCombined_rgn, $hOuter_rgn, $hInner_rgn, $RGN_DIFF)
    _WinAPI_DeleteObject($hOuter_rgn)
    _WinAPI_DeleteObject($hInner_rgn)

    _WinAPI_SetWindowRgn($g_hSelectorGUI, $hCombined_rgn)
EndFunc   ;==>UpdateSelector

Func ControlRelativeToDesktop($hWnd, $idControl)
    Local $Point, $aControlXYPos

    Dim $aPos[4]

    $aControlXYPos = ControlGetPos($hWnd, "", $idControl)

    $Point = DllStructCreate("int;int")
    DllStructSetData($Point, 1, $aControlXYPos[0])
    DllStructSetData($Point, 2, $aControlXYPos[1])
    DllCall("User32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "ptr", DllStructGetPtr($Point))

    ;x
    $aPos[0] = DllStructGetData($Point, 1)

    ;y
    $aPos[1] = DllStructGetData($Point, 2)

    ;width
    $aPos[2] = $aControlXYPos[2]

    ;height
    $aPos[3] = $aControlXYPos[3]

    Return $aPos
EndFunc   ;==>ControlRelativeToDesktop

 

Edited by Herb191
Fixed small error in code.

Share this post


Link to post
Share on other sites
jguinch

Instead of using WinAPI functions, what about using a simple label ? If what you need is just a border color, it could by sufficient.

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

Local $hMain = GUICreate("GUI", 400, 400, -1, -1, $WS_SIZEBOX + $WS_MAXIMIZEBOX, $WS_EX_COMPOSITED)

Local $id_button = GUICtrlCreateButton("Button", 100, 100, 200, 50)
GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

_CreateBorder($hMain, "", $id_button, 3, 0xFF0000)
GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

GUISetState()

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Exit
WEnd


Func _CreateBorder($hGui, $sText, $vCtrl, $iWidth, $iColor)
    Local $aPos = ControlGetPos($hGui, $sText, $vCtrl)
    Local $idLabel = GUICtrlCreateLabel("", $aPos[0] - $iWidth, $aPos[1] -  $iWidth, $aPos[2] + $iWidth * 2, $aPos[3] + $iWidth * 2)
    GUICtrlSetState(-1, $GUI_DISABLE)
    GUICtrlSetBkColor(-1, $iColor)
    Return $idLabel
EndFunc

 

Share this post


Link to post
Share on other sites
Herb191

I played with that option but the selector/border will actually be over the top of some image controls so labels don’t always display properly. The button control itself will be hidden. I am just using the button control to calculate the dimensions of the selector/border when the window gets resized. Also, I need the width of the selector’s border to stay the same even when the area is changing size.

Share this post


Link to post
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

×