Jump to content

Recommended Posts

Posted (edited)

Hello everybody :)
I got an issue with the following script (tested on Windows 11)

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

Opt("MustDeclareVars", 1)
Global $g_hGui

Example()

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

    Local $idButton, $idLabel, $idCheckbox, $idEdit
    $g_hGui = GUICreate("Drag controls (GUI_ONTOP issue)", 400, 150)

    $idButton = GUICtrlCreateButton("", 10, 30, 80, 80, $WS_CLIPSIBLINGS)
    GUICtrlSetData(-1, "Button " & $idButton)

    $idLabel = GUICtrlCreateLabel("", 100, 40, 80, 60, BitOr($SS_CENTERIMAGE, $SS_CENTER, $WS_CLIPSIBLINGS))
    GUICtrlSetData(-1, "Label " & $idLabel)
    GUICtrlSetBkColor(-1, 0x00FF00) ; green

    $idCheckbox = GUICtrlCreateCheckbox("", 190, 50, 80, 40, $WS_CLIPSIBLINGS)
    GUICtrlSetData(-1, "Checkbox " & $idCheckbox)
    GUICtrlSetBkColor(-1, 0xFFFF00) ; yellow

    $idEdit = GUICtrlCreateEdit("", 280 ,40, 100, 70, BitOr($GUI_SS_DEFAULT_EDIT, $WS_CLIPSIBLINGS))
    GUICtrlSetData(-1, "Edit " & $idEdit)

    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                Exit
            Case $GUI_EVENT_PRIMARYDOWN
                _ControlMove()
        EndSwitch
    WEnd
EndFunc   ;==>Example

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

    Local $aInfo, $idControl, $hControl, $aPos, $iSubtractX, $iSubtractY, $iLoopCount
    $aInfo = GUIGetCursorInfo($g_hGUI)

    If Not @error And $aInfo[4] Then
        $idControl = $aInfo[4]
        $hControl = GUICtrlGetHandle($idControl)
        $aPos = ControlGetPos($g_hGui, "", $idControl)
        $iSubtractX = $aInfo[0] - $aPos[0]
        $iSubtractY = $aInfo[1] - $aPos[1]

        While $aInfo[2] ; LMB pressed
            $iLoopCount += 1
            If $iLoopCount = 1 Then
                ; GUICtrlSetState($idControl, $GUI_ONTOP) ; changes wrongly the z-order of a label control, why ?
                ; _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0,  BitOr($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))
            EndIf
            $aInfo = GUIGetCursorInfo($g_hGui)
            GUICtrlSetPos($idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY)
            Sleep(10)
        WEnd
    EndIf
EndFunc   ;==>_ControlMove

1) When you run the script "as-is" (without modifying any line) :
* Each control dragged to the right covers the controls found at its right
* Each control dragged to the left is covered by the controls found at its left.

2) Now let's uncomment the $GUI_ONTOP line :

GUICtrlSetState($idControl, $GUI_ONTOP) ; seems to change wrongly the z-order of a label control, why ?

; _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0,  BitOr($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))

* Button, Checkbox, Edit : they all behave correctly, covering all controls when dragged.
* Label : on the contrary, the label control is covered by any control when dragged.

So the question is : why the label control doesn't follow the other controls behavior ?

3) Final test : please comment out the $GUI_ONTOP line and uncomment the _WinAPI_SetWindowPos line, like this :

; GUICtrlSetState($idControl, $GUI_ONTOP) ; changes wrongly the z-order of a label control, why ?

_WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0,  BitOr($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))

Now the label control behaves differently and covers all other controls when dragged.
So is there a bug with $GUI_ONTOP when applied to label controls ?

For the record, a track ticket #2287 concerning this question was closed by Jon 12 years ago.
But isn't the test in 2) enough to show that the label behaves differently from the other controls when $GUI_ONTOP is applied to it ?

Edit 1: no more sure of anything as the $WS_CLIPSIBLINGS style seems to interfere with all this !

Edit 2 : even if you remove the 4 $WS_CLIPSIBLINGS style at control creation, you'll notice that test 2) shows a different behavior when it comes to the label control, compared to the 3 other controls, but test 3) shows the same behavior for all controls.

That's why I prefer to use _WinAPI_SetWindowPos which behaves in the same way for the 4 controls, rather than $GUI_ONTOP which treats labels control differently, especially in this kind of script where we want the dragged control to appear above (in front of) any other control during the drag process.

Edited by pixelsearch
added Edit1 then Edit2

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted

Yeah it looks like $GUI_ONTOP sends labels to the wrong end of the z-order.

Just thought I'd add that the example in the track ticket #2287 seems to kind-of work...

"Set ONTOP Label 2" is printed when Label 2 comes to the front... but it's not clipping siblings.  When you click in the area where the 2 controls overlap, its the control underneath that receives the click.  So I take that to mean the "top" control here is being painted into areas where it shouldn't be.

#include <GUIConstants.au3>

GUICreate("Test", 300, 200)
GUISetState()

$idLab1 = GUICtrlCreateLabel("Label 1", 30, 30, 200, 100)
GUICtrlSetBkColor(-1, 0xFF0000)
$idLab2 = GUICtrlCreateLabel("Label 2", 50, 50, 200, 100)
GUICtrlSetBkColor(-1, 0x00FF00)

Local $iMsg
While 1
    $iMsg = GUIGetMsg()
    Switch $iMsg
        Case $idLab1, $idLab2
            ConsoleWrite("Set ONTOP " & GUICtrlRead($iMsg) & @CRLF)
            GUICtrlSetState($iMsg, $GUI_ONTOP)
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd
Posted

Thanks guys for your comments :)

I just rested with older versions of AutoIt, hoping secretly to detect if $GUI_ONTOP behaved correctly for the 4 controls in my initial script from post 1. Bingo !

Reminder of test 2) : $GUI_ONTOP line uncommented, _WinAPI_SetWindowPos line commented out, like this :

GUICtrlSetState($idControl, $GUI_ONTOP) ; changes wrongly the z-order of a label control, why ?

; _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0,  BitOr($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))

* AutoIt 3.3.12.0 (2014)
The script works fine for ALL 4 controls, which are correctly on top when dragged (label control too, yes !)

* AutoIt 3.3.14.0 (2015)
The script doesn't work for all controls : the label control doesn't behave as the 3 other controls.

Which means that some code has changed between these 2 versions and the timeline shows that it is connected to Track ticket #2287 owned and closed by Jon, who wrote in the AutoIt history/changelog :

Fixed #2287: GUICtrlSetState() $GUI_ONTOP not set.

Unfortunately, what worked fine (at least for me) with the previous version from 2014 doesn't work anymore with the version from 2015 and further. For the record, I don't understand trancexx answer in the track ticket, quote :

Changed 13 years ago by trancexx
Resolution set to No Bug
Status changed from new to closed

$GUI_ONTOP does what it's docummented that it does. There is no bug here.
Documentation says that control will get to the top of z-order. By default if the control is on top, it's the closest to the parent window (GUI) and it's therefore covered by all other controls being lower down the z-order.

On the other hand, for example, if the GUI would have WS_EX_COMPOSITED ex-style, you would see different effect (also docummented).

Maybe I'm wrong, but an "ontop" control is not covered by all other sibling controls. On the contrary, it is supposed to be in front of us, before all other controls, with the greatest z-order index of the sibling controls. What would be the point of sending it at the bottom of the controls stack, hidden by all of them, and name the variable $GUI_ONTOP ?

I know the actual doc indicates what follows for $GUI_ONTOP, but maybe it has been badly retranscripted in the help file :

$GUI_ONTOP (2048) : Control will be have the ontop attribute for the window (zOrdering).

Also, I have no idea where this link took its source from, in 2017, to indicate a more complete definition :

$GUI_ONTOP : Control will be given the ontop attribute, making it show on top of other elements (zOrdering).

What I may simply do one of these days, it's to add a new comment in trac ticket #2287, linking to the thread we are in, and we'll see what happens : if nothing can be done, at least we'll have the _WinAPI_SetWindowPos function that behaves the same way for all controls.

 

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted

Yeah, not sure about trancexx's comment - it doesn't sound right given $HWND_TOP works as expected.

 $WS_EX_COMPOSITED does say it "paints all descendants of a window in bottom-to-top painting order".  I take that as it'll paint each control (within an area) one at a time into a buffer so you can mix alpha channels, then dump the result to the screen.. I don't think the description is alluding to changes in the z-ordering - I'd say its more it's pointing out controls aren't just getting painted on top with some auto-clipping.

Posted (edited)

@MattyD Hey Matt ( I read Matt in the track ticket you opened :D )

First of all thanks for the track ticket, I hope the script you presented there will also be tested with the AutoIt versions I indicated above, because it works like a charm with AutoIt 3.3.12.0 (2014) included (tested)

For the record, I'm trying to script a couple of functions that allow to save all the coords of an AutoIt Gui, its controls (including child and grandchild gui's and their own controls etc...) . Then when the script is run again, everything should be restored at the same position as it was saved.

I'm testing the functions not only with the script found in my 1st post above, but with a bit more complex script containing...

LV(detachedheader)v4.png.2a807f5a993718b3b0eed875f3b6652c.png

1) A resizable GUI (top-level)
2) All its controls are movable and resizable, on top while dragged ;)
3) A child GUI (resizable) containing a Listview control, which makes the Listview resizable while resizing its container (the child GUI)
4) This lisview is created with a $LVS_NOCOLUMNHEADER style to prevent flicker while resizing
5) A grandchild GUI (parent is the child GUI) containing a detached header created with _GUICtrlHeader_Create, this will remind plenty of things to @WildByDesign
6) The ListView seems "flicker free" while resizing anything (many thanks to @ioa747 for the tests and advices) and has been tested on Windows 11 with 10.000 lines and 10 columns. It's flicker-free because of some appropriate styles placed at the right moments (these styles being different depending on older or newer OS !), thanks to @LarsJ for his posts and his infos. I'll soon post in a new thread all the code related to this ListView, even if there is plenty of code (maybe the price to pay to get a flicker-free listview ?)

Now back to the functions that save and restore coords. The 3 lines added in my 1st post are :

#include "_SaveCoord.au3" ; 1st added line
...
_SaveCoord(1) ; 2nd added line
GUISetState()
...
Case $GUI_EVENT_CLOSE
    _SaveCoord(2) ; 3rd added line
    Exit

As you see, there are no Gui's handles or control ID's passed as arguments when calling _SaveCoord(1 or 2)  so it makes the function more or less "portable" for other scripts working on AutoIt GUI's

Here is the code of my 1st post, amended with the 3 lines mentioned above.

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

#include "_SaveCoord.au3"

Opt("MustDeclareVars", 1)
Global $g_hGui

Example()

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

    Local $idButton, $idLabel, $idCheckbox, $idEdit
    $g_hGui = GUICreate("Drag controls & _SaveCoord", 400, 150)

    $idButton = GUICtrlCreateButton("", 10, 30, 80, 80, $WS_CLIPSIBLINGS)
    GUICtrlSetData(-1, "Button " & $idButton)

    $idLabel = GUICtrlCreateLabel("", 100, 40, 80, 60, BitOr($SS_CENTERIMAGE, $SS_CENTER, $WS_CLIPSIBLINGS))
    GUICtrlSetData(-1, "Label " & $idLabel)
    GUICtrlSetBkColor(-1, 0x00FF00) ; green

    $idCheckbox = GUICtrlCreateCheckbox("", 190, 50, 80, 40, $WS_CLIPSIBLINGS)
    GUICtrlSetData(-1, "Checkbox " & $idCheckbox)
    GUICtrlSetBkColor(-1, 0xFFFF00) ; yellow

    $idEdit = GUICtrlCreateEdit("", 280 ,40, 100, 70, BitOr($GUI_SS_DEFAULT_EDIT, $WS_CLIPSIBLINGS))
    GUICtrlSetData(-1, "Edit " & $idEdit)

    _SaveCoord(1)
    GUISetState()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                _SaveCoord(2)
                Exit
            Case $GUI_EVENT_PRIMARYDOWN
                _ControlMove()
        EndSwitch
    WEnd
EndFunc   ;==>Example

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

    Local $aInfo, $idControl, $hControl, $aPos, $iSubtractX, $iSubtractY, $iLoopCount
    $aInfo = GUIGetCursorInfo($g_hGUI)

    If Not @error And $aInfo[4] Then
        $idControl = $aInfo[4]
        $hControl = GUICtrlGetHandle($idControl)
        $aPos = ControlGetPos($g_hGui, "", $idControl)
        $iSubtractX = $aInfo[0] - $aPos[0]
        $iSubtractY = $aInfo[1] - $aPos[1]

        While $aInfo[2] ; LMB pressed
            $iLoopCount += 1
            If $iLoopCount = 1 Then
                _WinAPI_SetWindowPos($hControl, $HWND_TOP, 0, 0, 0, 0,  BitOr($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))
            EndIf
            $aInfo = GUIGetCursorInfo($g_hGui)
            GUICtrlSetPos($idControl, $aInfo[0] - $iSubtractX, $aInfo[1] - $iSubtractY)
            Sleep(10)
        WEnd
    EndIf
EndFunc   ;==>_ControlMove

And here is the _SaveCoord.au3 file, to be placed in the same directory as the tested script :

_SaveCoord.au3  (new version #3, Feb 25, 2026)  (download counter erased by new version)

The coords should be restored correctly as long as you don't add/remove controls in the GUI. Now if the code changes (new controls added, or having their ID's change) then the .coord file will be deleted (after a warning message) then recreated when you run the script again.

If you got some free time, could you please indicate what you think should be done to improve the _SaveCoord() function as I just finished scripting it and it certainly can be improved to make it more robust.

Thanks for reading :)

Edited by pixelsearch
_SaveCoord.au3 : new version #3 (Feb 25, 2026)

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted
39 minutes ago, pixelsearch said:

For the record, I'm trying to script a couple of functions that allow to save all the coords of an AutoIt Gui, its controls (including child and grandchild gui's and their own controls etc...) . Then when the script is run again, everything should be restored at the same position as it was saved.

This is incredible, @pixelsearch. I have always wished for such functionality to be able to restore the previous coordinates and especially after the GUI has been resized. I've tested your example, added $WS_OVERLAPPEDWINDOW to the GUICreate, resized, moved, etc. and everything restores perfectly from my limited testing so far.

I will continue to test more later and see if anything can (or needs to be) changed or improved.

I would imagine that, depending on a particular apps' needs, the developer using this script could modify it slightly to save those coordinates to the registry and restore from registry. Depending on whether the dev wants the app to be portable or not.

Actually I'm a little bit curious now as to whether or not we could write/read these coordinates from the NTFS Alternate Data Streams for the script file on disk or, if compiled, the compiled binary executable.

Posted (edited)
On 2/17/2026 at 2:01 PM, WildByDesign said:

[...] and everything restores perfectly from my limited testing so far.
I will continue to test more later and see if anything can (or needs to be) changed or improved.

Thanks for your test and the positive comment :)
I'm already sure that in the next version, I'll check at least if a control ID (#5 for example) saved in the last session (with its class name, style etc...) has the same class name as the corresponding control ID #5 which is about to be displayed in the new session. [done in version #2]

If the class names are different for a same control ID #, then there is no point in restoring anything for any element of the GUI. This kind of checking should be done before restoring any coord, because if you already restored a few control coords, then find a "non-matching" one (ID# 5), it will be difficult to revert the Winmove and GUICtrlSetPos that you just did ! In fact when this happens, the .coord file containing the saved coords should be automatically deleted by the script (after a warning indicating why) then recreated when you run the script again. [done in version #2]

For the record, the _SaveCoord() function should work even if there are several AutoIt top-level windows in the same thread, for example 2 GUI's, or 1 GUI + an mdichild window (recognized as top-level by _WinAPI_EnumThreadWindows), e.g. all GUI's created with the function GuiCreate() when the style WS_CHILD is not indicated.

I didn't test these cases yet (2 gui's etc...) but in theory it should work, because of this line...

Local $aEnumTopLevel = _WinAPI_EnumThreadWindows(0, False) ; Enum. all non-child windows of this thread. False retrieves also hidden windows

...which will retrieve several handles having an "AutoIt v3 GUI" class name.

Just a reminder : you sure remember the thread you created : Why do controls always revert to initial position while resizing GUI?  ( I like this thread title :D )
It shows that GUICtrlSetPos is the (only ?) function to use when moving AutoIt GUI controls, if you want them to keep their new position when the Gui is resized, maximized, restored, without adding any extra code.

The 3 other functions I know (e.g. WinMove, ControlMove, _WinAPI_SetWindowPos) always revert, so why should be use them and always face this same issue ?

Maybe that's one of the reasons why the AutoIt dev's say from the beginning : use GUI functions for your GUI controls (though we saw in a couple of posts it is not always true and sometimes you have to use a "non-gui" function to achieve correctly your goal). Anyway, experiment and experiment again when facing these issues, as there is nothing 100% sure.

Edited by pixelsearch
added note [done in version #2]

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted
4 hours ago, pixelsearch said:

Just a reminder : you sure remember the thread you created : Why do controls always revert to initial position while resizing GUI?  ( I like this thread title :D )
It shows that GUICtrlSetPos is the (only ?) function to use when moving AutoIt GUI controls, if you want them to keep their new position when the Gui is resized, maximized, restored, without adding any extra code.

Absolutely. I thought I was losing my mind with that issue. I definitely learned a good lesson there. Also some difference between GUISetState and WinSetState I think it was where I learned some lessons somewhat recently.

4 hours ago, pixelsearch said:

Maybe that's one of the reasons why the AutoIt dev's say from the beginning : use GUI functions for your GUI controls (though we saw in a couple of posts it is not always true and sometimes you have to use a "non-gui" function to achieve correctly your goal). Anyway, experiment and experiment again when facing these issues, as there is nothing 100% sure.

Yes, indeed. Aside from the built-in GUI functions, I have always had a tendency to use the WinAPI functions because I really like them. But I’ve realized a handful of times recently that the built-in AutoIt functions are quite often faster. Although not always. I quite often performance test any related functions now for comparison. At least when it comes to functions which are used in rapid succession.

Posted
On 2/17/2026 at 11:12 PM, pixelsearch said:

If you got some free time, could you please indicate what you think should be done to improve the _SaveCoord() function as I just finished scripting it and it certainly can be improved to make it more robust.

I might have some time over the weekend to look a bit closer - but at a glance, it seems like a pretty good implementation mate :).

Posted (edited)
On 2/19/2026 at 11:45 AM, MattyD said:

but at a glance, it seems like a pretty good implementation mate :).

Thanks for that :)

Update Feb 20, 2026 : new version #2 of _SaveCoord.au3 in this post above.

Changes : splitted the main function _SaveCoord() in 4 functions.
One of the functions is used to check possible mismatch between the previous and current session, for example :
1) if the number of components has changed (one control added or removed)
2) if each corresponding row (previous array vs current array) has the same class name + same control id + same style (i.e. no change in code by reclassing the controls etc...)

If one of these cases is encountered, then a warning message indicates the problem, then the coord file is automatically deleted as it became inconsistent. It will be recreated the next time the script is run.

Update Feb 25, 2026 : new version #3 of _SaveCoord.au3 in this post above.

Added ", 8" to this line :

$aData[$iRow][9] = "0x" & Hex(_WinAPI_GetWindowLong($hWnd, $GWL_STYLE), 8) ; normalize 32/64 bits (64 bits returns 16 length with 8 leading 0's : tested)
Edited by pixelsearch
_SaveCoord.au3 : new version #3 (Feb 25, 2026)

"I think you are searching a bug where there is no bug... don't listen to bad advice."

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
×
×
  • Create New...