Sign in to follow this  
Followers 0
wraithdu

Keep Child GUI On Top of Parent GUI

14 posts in this topic

I have a two GUI app. It opens with the parent GUI active and showing, then when the child GUI with $WS_EX_TOOLWINDOW style is opened via a button, the parent GUI is disabled (not hidden) and the child GUI is shown.

How can I keep this child GUI always on top of the parent, but not necessarily on top of all windows (ie $WS_EX_TOPMOST)?

What can happen otherwise is that if another window is activated over top this app, then when activating it via the parent GUI's taskbar button (remember the child is a TOOLWINDOW and does not have a taskbar button and no ALT-TAB), the parent GUI is shown but not the child GUI. There's no way to get to the child without minimizing everything else.

Thanks!

Share this post


Link to post
Share on other sites



I have a two GUI app. It opens with the parent GUI active and showing, then when the child GUI with $WS_EX_TOOLWINDOW style is opened via a button, the parent GUI is disabled (not hidden) and the child GUI is shown.

How can I keep this child GUI always on top of the parent, but not necessarily on top of all windows (ie $WS_EX_TOPMOST)?

What can happen otherwise is that if another window is activated over top this app, then when activating it via the parent GUI's taskbar button (remember the child is a TOOLWINDOW and does not have a taskbar button and no ALT-TAB), the parent GUI is shown but not the child GUI. There's no way to get to the child without minimizing everything else.

Thanks!

If it's a child window then it will stay on top of the parent if it's made like this example

#include <guiconstants.au3>
#include <constants.au3>

$hGui1 = GUICreate('Parent',800,600,100,100, BitOr($WS_POPUP,$WS_SIZEBOX,$GUI_SS_DEFAULT_GUI,$WS_CLIPCHILDREN))
$iBtn1 = GUICtrlCreateButton("fit",560,10,100,21,$WS_CLIPSIBLINGS)
$hLV1 = GUICtrlCreateListView("lvexample",410,50,300,300)
GUISetState()
$child = GUICreate("child",100,100,100,100,-1,$WS_EX_TOOLWINDOW)

WinMove("child","",0,0,395,600);put it in the top left 
DllCall("user32.dll", "int", "SetParent", "hwnd", $child, "hwnd", $hGui1)
GUISetState()

While 1
    $msg = GUIGetMsg()
    If $msg = -3 Then Exit
    If $msg = $iBtn1 Then 
       GUISetState(@SW_RESTORE, $child)
       WinMove($child,"",0,0,295,470)
     EndIf
    
WEnd

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Thanks for the example, but I guess my 2nd GUI isn't truly a "child" window by your script. It's just a 2nd GUI window with the TOOLWINDOW style. It's exactly like your script without the DllCall command. Any way to do what I want under those circumstances?

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Try this:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Constants.au3>
Global $enabled = 0
Global $child = 0
Global $close_button = 78219
$hGui1 = GUICreate('Parent',500,500)
$iBtn1 = GUICtrlCreateButton("Open Child", 400, 11, 80, 27)
GUISetState()
While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
            Exit
        Case Not $enabled And Not WinExists($child)
            $enabled = 1
            GUISetState(@SW_ENABLE, $hGui1)
        Case $msg = $iBtn1
            $child = GUICreate("child",200,200,-1,-1,$WS_EX_TOOLWINDOW,-1,$hGui1)
            $close_button = GUICtrlCreateButton("Close", 11, 11, 68, 27)
            GUISetState()
            $enabled = 0
            WinSetOnTop($child, "", 1)
            GUISetState(@SW_DISABLE, $hGui1)
        Case $msg = $close_button
            GUIDelete($child)
            $enabled = 1
            GUISetState(@SW_ENABLE, $hGui1)
    EndSelect
    If WinExists($child) Then
        If Not WinActive($child) Then
            WinSetOnTop($child, "", 0)
        Else
            WinSetOnTop($child, "", 1)
        EndIf
    EndIf
    Sleep(40)
WEnd

I think this is what you want, but it doesn't work perfectly

Edited by Squirrely1

Das Häschen benutzt Radar

Share this post


Link to post
Share on other sites

Thanks! The WinSetOnTop loop is the ticket I think. I'm a little wary of CPU usage though, the app could be running in the backgroup as a tray icon for the duration of a user session. Oh, and for reference, I'm using OnEventMode, so it would be something like

While 1
     If Not WinActive($child) Then
        WinSetOnTop($child, "", 0)
     Else
        WinSetOnTop($child, "", 1)
     EndIf
     Sleep(250)
WEnd

Maybe I could dial down the loop, I really only need the child brought to the top when the parent's taskbar button is pressed.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Ahhh, this works MUCH better

If Not WinActive($hGui1) Then
    WinSetOnTop($child, "", 0)
Else
    WinSetOnTop($child, "", 1)
EndIf
Sleep(30)

Much smoother transitions with the test on the parent GUI. Thanks for the pointer in the right direction.

Edited by wraithdu

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Thanks for the example, but I guess my 2nd GUI isn't truly a "child" window by your script. It's just a 2nd GUI window with the TOOLWINDOW style. It's exactly like your script without the DllCall command. Any way to do what I want under those circumstances?

Easiest way is to have something in your idle loop that checks to see if the parent becomes active when you want the focus on the child.

If the child is forced to be active then you might need something on the child to allow you to get back to the parent.

#include <guiconstants.au3>
#include <constants.au3>

$hGui1 = GUICreate('Parent', 800, 600, 100, 100, BitOR($WS_POPUP, $WS_SIZEBOX, $GUI_SS_DEFAULT_GUI, $WS_CLIPCHILDREN))
$iBtn1 = GUICtrlCreateCheckbox("keep child on top", 560, 10, 100, 21)
$hLV1 = GUICtrlCreateListView("lvexample", 410, 50, 300, 300, $WS_CLIPSIBLINGS)
GUISetState()
$child = GUICreate("child", 150, 100, 150, 150, -1, $WS_EX_TOOLWINDOW)
$chk2 = GUICtrlCreateCheckbox("allow parent on top",20,20,160,20)
GUISetState()

$keepchildontop = False

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case - 3
            Exit
        Case $iBtn1
            If BitAND(GUICtrlRead($iBtn1), $GUI_CHECKED) = $GUI_CHECKED Then
                $keepchildontop = True
                GUICtrlSetState($chk2,$GUI_UNCHECKED)
            Else
                $keepchildontop = False
                GUICtrlSetState($chk2,$GUI_CHECKED)
            EndIf
        Case $chk2
            $keepchildontop = BitAND(GUICtrlRead($chk2),$GUI_CHECKED) = $GUI_UNCHECKED
            GUICtrlSetState( $iBtn1,$GUI_CHECKED + $GUI_UNCHECKED - GUICtrlRead($chk2))
            
    EndSwitch

    If $keepchildontop Then
            If WinActive($hGui1) Then WinActivate($child)
    EndIf
    
WEnd

EDIT: I was a bit slow there. Squirrely1's example works well.

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

In the past I have tried for some hours to make the Parent and Child thing work, and wraithdu's upgrade finally makes this script work great now:

CODE
#include <GUIConstantsEx.au3>

#include <WindowsConstants.au3>

;#include <Constants.au3>

Global $enabled = 0

Global $child = 0

Global $close_button = 78

$hGui1 = GUICreate('Parent',500,500)

$iBtn1 = GUICtrlCreateButton("Open Child", 400, 11, 80, 27)

GUISetState()

While 1

$msg = GUIGetMsg()

Select

Case $msg = $GUI_EVENT_CLOSE

Exit

Case Not $enabled And Not WinExists($child)

$enabled = 1

GUISetState(@SW_ENABLE, $hGui1)

Case $msg = $iBtn1

$child = GUICreate("child",200,200,-1,-1,-1,$WS_EX_TOOLWINDOW,$hGui1)

$close_button = GUICtrlCreateButton("Close", 11, 11, 68, 27)

GUISetState()

$enabled = 0

WinSetOnTop($child, "", 1)

GUISetState(@SW_DISABLE, $hGui1)

Case $msg = $close_button

GUIDelete($child)

$enabled = 1

GUISetState(@SW_ENABLE, $hGui1)

EndSelect

If Not WinActive($hGui1) Then

WinSetOnTop($child, "", 0)

Else

If WinExists($child) Then

WinSetOnTop($child, "", 1)

EndIf

EndIf

Sleep(40)

WEnd

But you are a real programmer, martin, not just mostly cute like me. How would you improve this code? It looks like it does too much checking to see if windows are active and if they exist, and that maybe it uses too much memory.

Edited by Squirrely1

Das Häschen benutzt Radar

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

If you're not going to allow the parent dialog to be selected while the child dialog is visible, then you might as well not have the parent dialog enabled to begin with once you set the child to be visible...

#Include <GUIConstantsEx.au3>
#Include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)

; Parent --------------
Global $hParent = GUICreate("Parent", 320, 240)
GUICtrlSetOnEvent(GUICtrlCreateButton("Show Child", 5, 5), "showChild")

; Child --------------
Global $hChild = GUICreate("Child", 210, 160, Default, Default, Default, $WS_EX_TOOLWINDOW, $hParent)
GUICtrlSetOnEvent(GUICtrlCreateButton("Hide Child", 5, 5), "hideChild")

; Miscellaneous ---------
GUISetOnEvent($GUI_EVENT_CLOSE, "appExit", $hParent)
GUISetOnEvent($GUI_EVENT_CLOSE, "hideChild", $hChild)
GUISetState(@SW_SHOW, $hParent)

While 1
    Sleep(1000)
WEnd

; Functions ---------
Func showChild()
    GUISetState(@SW_DISABLE, $hParent)
    GUISetState(@SW_SHOW, $hChild)
    WinActivate($hChild)
EndFunc

Func hideChild()
    GUISetState(@SW_ENABLE, $hParent)
    GUISetState(@SW_HIDE, $hChild)
    WinActivate($hParent)
EndFunc

Func appExit()
    Exit
EndFunc

(I'm not sure if this is what wraithdu is looking for, but it works like how Squirrely1's script does without the overhead)

Edited by -Ultima-

[ WinINet.au3 | Array.au3 (Optimized) | _UnixTimeParse() ]

Share this post


Link to post
Share on other sites

OMG, how did I miss the [parent] declaration in GUICreate?!?!? Son of a....:D

Share this post


Link to post
Share on other sites

But you are a real programmer, martin, not just mostly cute like me. How would you improve this code? It looks like it does too much checking to see if windows are active and if they exist, and that maybe it uses too much memory.

If I am a real programmer then so are we all. I haven't got any better solutions than anyone else in this thread.

I don't think your script would use up too much memory though.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#13 ·  Posted

Sorry for some resurrecting activity, but I wasn't happy that the issue raised by the OP had been satisfied in this thread, and especially, I wasn't satisfied with my code, when I found this thread in a search.

So, here is a new, working version for use with MessageLoop mode, Opt("GUIOnEventMode", 0) -

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
;#include <ButtonConstants.au3>; needed if any button styles are used.

Opt("MustDeclareVars", 1)

;The following line replaces $GUI_SS_DEFAULT_GUI because it doesn't appear in AutoIt v3.2.10.0 -
Global Const $DEFAULT_GUISTYLES = BitOR($WS_MINIMIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_SYSMENU)
Global $parentIsEnabled, $parent_gui, $btn_open, $child_gui, $btn_close, $msg

$parent_gui = GUICreate("Parent GUI", 500, 500, -1, -1, _
        BitOR($DEFAULT_GUISTYLES, $WS_CLIPCHILDREN, $WS_SIZEBOX))
$btn_open = GUICtrlCreateButton("Open Child", 400, 11, 80, 27)

$parentIsEnabled = True

$child_gui = GUICreate("Child GUI", 200, 200, -1, -1, _
        BitOR($DEFAULT_GUISTYLES, $WS_CLIPSIBLINGS), $WS_EX_TOOLWINDOW, $parent_gui)

GUISetState(@SW_SHOW, $parent_gui)
GUISwitch($parent_gui)
While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
            If $parentIsEnabled Then
                ExitLoop
            Else
                GUISetState(@SW_HIDE, $child_gui)
                GUISetState(@SW_ENABLE, $parent_gui)
                $parentIsEnabled = True
                GUISwitch($parent_gui)
            ; the following line seems to be needed when running AutoIt v3.2.11.10 -
                WinActivate($parent_gui)
            EndIf
            
        Case $msg = $btn_open
            GUISetState(@SW_DISABLE, $parent_gui)
            $parentIsEnabled = False
            GUISetState(@SW_SHOW, $child_gui)
            GUISwitch($child_gui)
            
    EndSelect
    Sleep(40)
WEnd

And here is a new version for use with the OnEvent mode, Opt("GUIOnEventMode", 1) -

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
;#include <ButtonConstants.au3>; needed if any $BS_ button styles are used.

Opt("GUIOnEventMode", 1)
Opt("MustDeclareVars", 1)

Global $parentIsEnabled, $parent_gui, $btn_open, $child_gui, $btn_close, $msg

;The following line replaces $GUI_SS_DEFAULT_GUI because it doesn't appear in AutoIt v3.2.10.0 -
Global Const $DEFAULT_GUISTYLES = BitOR($WS_MINIMIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_SYSMENU)

$parent_gui = GUICreate("Parent GUI", 500, 500, -1, -1, _
        BitOR($DEFAULT_GUISTYLES, $WS_CLIPCHILDREN, $WS_SIZEBOX))
$btn_open = GUICtrlCreateButton("Open Child", 400, 11, 80, 27)

$parentIsEnabled = True

$child_gui = GUICreate("Child GUI", 200, 200, -1, -1, _
        BitOR($DEFAULT_GUISTYLES, $WS_CLIPSIBLINGS), $WS_EX_TOOLWINDOW, $parent_gui)

GUISwitch($parent_gui)

GUICtrlSetOnEvent($btn_open, "showChild")
GUISetOnEvent($GUI_EVENT_CLOSE, "appExit", $parent_gui)
GUISetOnEvent($GUI_EVENT_CLOSE, "hideChild", $child_gui)

GUISetState(@SW_SHOW, $parent_gui)

While 1
    Sleep(40)
WEnd

Func appExit()
    Exit
EndFunc  ;==>appExit

Func hideChild()
    GUISetState(@SW_HIDE, $child_gui)
    GUISetState(@SW_ENABLE, $parent_gui)
    GUISwitch($parent_gui)
    $parentIsEnabled = True
; the following line seems to be needed when running AutoIt v3.2.11.10 -
    WinActivate($parent_gui)
EndFunc  ;==>hideChild

Func showChild()
    GUISetState(@SW_DISABLE, $parent_gui)
    $parentIsEnabled = False
    GUISetState(@SW_SHOW, $child_gui)
    GUISwitch($child_gui)
EndFunc  ;==>showChild

I found out two things doing this:

1. Using the beta 3.2.11.10, this was strangely required in both snippets: WinActivate($parent_gui)

2. A definition for $GUI_SS_DEFAULT_GUI was missing from the WindowsConstants.au3 in AutoIt v3.2.10.0 that was not missing from the beta version v3.2.11.10


Das Häschen benutzt Radar

Share this post


Link to post
Share on other sites

Squirrly,

I'm not sure if this is old news or not but it looks like the solution for having to activate the window is to show/enable the other before doing any hiding or disabling to the first.

Select
        Case $msg = $GUI_EVENT_CLOSE
            If $parentIsEnabled Then
                ExitLoop
            Else
    GUISetState(@SW_ENABLE, $parent_gui)
                GUISetState(@SW_HIDE, $child_gui)               
                $parentIsEnabled = True
                GUISwitch($parent_gui)
            EndIf
            
        Case $msg = $btn_open
GUISetState(@SW_SHOW, $child_gui)
            GUISetState(@SW_DISABLE, $parent_gui)
            $parentIsEnabled = False
            GUISetState(@SW_SHOW, $child_gui)
            GUISwitch($child_gui)
            
    EndSelect

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
Sign in to follow this  
Followers 0