Jump to content
Sign in to follow this  
Drifter

Problem with multiple GUI windows

Recommended Posts

Drifter

I hope i've placed this in the right forum. My issue is with a script in general, though the script happens to have GUI windows.

By default all the windows in my script act normally, but notice that while the progress bar is moving if you try to close the window (Clicking the "x") it will continue along its business and then the whole program dies after its done. My guess is that its because the close window button is passed to the other "GUIGetMsg" functions. how do i prevent this from happening so that the program just goes back to window 2 like its supposed to? Dont want the user causing any issues ;)

#include <GUIConstantsEx.au3>

Global $win_1, $win_2, $win_3

$win_1 = GUICreate("Window 1",400,400)
$button_1 = GUICtrlCreateButton("Open",10,10,100,50)

GUISetState()

While 1
    $msg = GUIGetMsg(1)
    
    Select
    Case $msg[0] = $button_1
        newWindow()
    Case $msg[0] = $GUI_EVENT_CLOSE
        Exit
    EndSelect
    
WEnd

Func newWindow()
    
    $win_2 = GUICreate("Window 2",300,200,-1,-1,-1,-1,$win_1)
    $button_2 = GUICtrlCreateButton("Start",10,10,100,50)
    
    GUISetState(@SW_DISABLE,$win_1)
    GUISetState(@SW_SHOW,$win_2)
    
    While 1
        $msg = GUIGetMsg(1)
        
        Select
        Case $msg[0] = $button_2
            startStuff()
        Case $msg[0] = $GUI_EVENT_CLOSE
            GUISetState(@SW_ENABLE, $win_1)
            GUIDelete($win_2)
            ExitLoop(1)
        EndSelect
        
    WEnd
EndFunc

Func startStuff()
    
    $win_3 = GUICreate("Doing something...",200,100,-1,-1,-1,-1,$win_2)
    $prog = GUICtrlCreateProgress(10,40,180,20)
    
    GUISetState(@SW_DISABLE,$win_2)
    GUISetState(@SW_SHOW,$win_3)
    
    For $i = 1 To 20
        Sleep(1000)
        GUICtrlSetData($prog, $i * 100 / 20)
    Next
    
    Sleep(3000)
    GUISetState(@SW_ENABLE, $win_2)
    GUIDelete($win_3)
    
EndFunc

Share this post


Link to post
Share on other sites
seandisanti

I hope i've placed this in the right forum. My issue is with a script in general, though the script happens to have GUI windows.

By default all the windows in my script act normally, but notice that while the progress bar is moving if you try to close the window (Clicking the "x") it will continue along its business and then the whole program dies after its done. My guess is that its because the close window button is passed to the other "GUIGetMsg" functions. how do i prevent this from happening so that the program just goes back to window 2 like its supposed to? Dont want the user causing any issues ;)

#include <GUIConstantsEx.au3>

Global $win_1, $win_2, $win_3

$win_1 = GUICreate("Window 1",400,400)
$button_1 = GUICtrlCreateButton("Open",10,10,100,50)

GUISetState()

While 1
    $msg = GUIGetMsg(1)
    
    Select
    Case $msg[0] = $button_1
        newWindow()
    Case $msg[0] = $GUI_EVENT_CLOSE
        Exit
    EndSelect
    
WEnd

Func newWindow()
    
    $win_2 = GUICreate("Window 2",300,200,-1,-1,-1,-1,$win_1)
    $button_2 = GUICtrlCreateButton("Start",10,10,100,50)
    
    GUISetState(@SW_DISABLE,$win_1)
    GUISetState(@SW_SHOW,$win_2)
    
    While 1
        $msg = GUIGetMsg(1)
        
        Select
        Case $msg[0] = $button_2
            startStuff()
        Case $msg[0] = $GUI_EVENT_CLOSE
            GUISetState(@SW_ENABLE, $win_1)
            GUIDelete($win_2)
            ExitLoop(1)
        EndSelect
        
    WEnd
EndFunc

Func startStuff()
    
    $win_3 = GUICreate("Doing something...",200,100,-1,-1,-1,-1,$win_2)
    $prog = GUICtrlCreateProgress(10,40,180,20)
    
    GUISetState(@SW_DISABLE,$win_2)
    GUISetState(@SW_SHOW,$win_3)
    
    For $i = 1 To 20
        Sleep(1000)
        GUICtrlSetData($prog, $i * 100 / 20)
    Next
    
    Sleep(3000)
    GUISetState(@SW_ENABLE, $win_2)
    GUIDelete($win_3)
    
EndFunc

while you're in your loop populating the progress bar, your loop that is checking for messages is stopped. msg is not re-evaluated until after your progress bar is complete. as far as why your exiting on the second window exits your script, from the help file:

when a new window is created it becomes the "default" window for future GUI operations (including control creation).

In the GUI Reference part of the help file read the onevent mode topic and it will tell you how to fix that

Share this post


Link to post
Share on other sites
Drifter

i dont exactly understand what youre trying to tell me. I close the progress bar window once its done, so its no longer the default window...... and if GUIGetMsg isnt updated then there should be no issue?

Share this post


Link to post
Share on other sites
Spiff59

If the user bangs on the exit button while you're doing stuff, the msg queue can stack up enough $GUI_EVENT_CLOSE characters to back you all the way out of your program. After your StartStuff() call you can add these 2 lines to clear out anything left in the queue when control returns from the function:

While GUIGetMsg() ; clear anything in msg queue
WEnd

Edit: You'd need to add an "If GuiGetMsg() = $GUI_EVENT_CLOSE Then..." test in your startstuff() loop to be able to bust out of that function prematurely.

Is this better behavior?

#include <GUIConstantsEx.au3>

Global $win_1, $win_2, $win_3

$win_1 = GUICreate("Window 1",400,400)
$button_1 = GUICtrlCreateButton("Open",10,10,100,50)

GUISetState()

While 1
    $msg = GUIGetMsg(1)

    Select
    Case $msg[0] = $button_1
        newWindow()
    Case $msg[0] = $GUI_EVENT_CLOSE
        Exit
    EndSelect

WEnd

Func newWindow()

    $win_2 = GUICreate("Window 2",300,200,-1,-1,-1,-1,$win_1)
    $button_2 = GUICtrlCreateButton("Start",10,10,100,50)

    GUISetState(@SW_DISABLE,$win_1)
    GUISetState(@SW_SHOW,$win_2)

    While 1
        $msg = GUIGetMsg(1)

        Select
        Case $msg[0] = $button_2
            startStuff()
            While GUIGetMsg() ; clear anything in msg queue
            WEnd
        Case $msg[0] = $GUI_EVENT_CLOSE
            GUISetState(@SW_ENABLE, $win_1)
            GUIDelete($win_2)
            ExitLoop(1)
        EndSelect

    WEnd
EndFunc

Func startStuff()

    $win_3 = GUICreate("Doing something...",200,100,-1,-1,-1,-1,$win_2)
    $prog = GUICtrlCreateProgress(10,40,180,20)

    GUISetState(@SW_DISABLE,$win_2)
    GUISetState(@SW_SHOW,$win_3)

    For $i = 1 To 20
        Sleep(100)
        If GUIGetMsg() = $GUI_EVENT_CLOSE Then ExitLoop
        GUICtrlSetData($prog, $i * 100 / 20)
        If GUIGetMsg() = $GUI_EVENT_CLOSE Then ExitLoop
    Next

    Sleep(100)
    GUISetState(@SW_ENABLE, $win_2)
    GUIDelete($win_3)

EndFunc
Edited by Spiff59

Share this post


Link to post
Share on other sites
Drifter

so if i understand correctly, this works because any non-zero value in an if/while statement is considered "boolean true", is that correct?

Share this post


Link to post
Share on other sites
Spiff59

Anything a user clicks on in a GUI is stacked up in a queue, if that GUI doesn't have a GUIGetMsg() statement to process (and delete from) that queue, then anything placed in there is still present and will be serviced by other GUIGetMsg() statements elsewhere in your script. You just needed to empty the queue so that leftover clicks from the third GUI are not still waiting in the queue to be processed by other GUI's.

On a side note, it appears updating a progressbar is resource intensive, as in the example I modified, it took two checks for $GUI_EVENT_CLOSE (one after the sleep(), and another after the GUISetData() statement) to make the exit from the progress bar responsive.

Edit: You could also modify the style of the thrid GUI to where it doesn't even have the minimize/maximize/exit buttons.

Edited by Spiff59

Share this post


Link to post
Share on other sites
Drifter

i thought of removing the minimize, maximize, and close buttons, but i see nowhere in common styles or extended styles that would do this. This would be the ideal situation because in my real status bar i expect no user input whatsoever.

Share this post


Link to post
Share on other sites
Spiff59

You'll have to add: #include <WindowsConstants.au3>

But neither the $WS_BORDER, $WS_POPUP, or $WS_POPUPWINDOW styles (of the GUICreate() statement) have the buttons. They all have a slightly different appearance.

Edited by Spiff59

Share this post


Link to post
Share on other sites
Drifter

is there a way to combine $WS_POPUPWINDOW with something so i get a title bar still? I tried $WS_CAPTION but then i get the close button which destroys the original point of using POPUPwindow. ;)

Share this post


Link to post
Share on other sites
Spiff59

Umm...

Did you try $WS_BORDER ?

Share this post


Link to post
Share on other sites
Drifter

ahhh, i fail.... lol thanks! seems like theres something goofy with the window size now, but im guessing its counting the title bar as part of the window height, i will make the needed changes.

Problem solved, thanks alot!

Share this post


Link to post
Share on other sites
doudou

Your script needs just a slight modification:

#include <GUIConstantsEx.au3>

Global $win_1, $win_2, $win_3

$win_1 = GUICreate("Window 1",400,400)
$button_1 = GUICtrlCreateButton("Open",10,10,100,50)

GUISetState()

While 1
    $msg = GUIGetMsg(1)
    
    Select
    Case $msg[0] = $button_1
        newWindow()
    Case $msg[0] = $GUI_EVENT_CLOSE
        Exit
    EndSelect
    
WEnd

Func newWindow()
    
    $win_2 = GUICreate("Window 2",300,200,-1,-1,-1,-1,$win_1)
    $button_2 = GUICtrlCreateButton("Start",10,10,100,50)
    
    GUISetState(@SW_DISABLE,$win_1)
    GUISetState(@SW_SHOW,$win_2)
    GUISwitch($win_2)
    
    While 1
        $msg = GUIGetMsg(1)
        
        Select
        Case $msg[0] = $button_2
            startStuff()
        Case $msg[0] = $GUI_EVENT_CLOSE
            ExitLoop(1)
        EndSelect
        
    WEnd
    GUISetState(@SW_ENABLE, $win_1)
    GUIDelete($win_2)
    GUISwitch($win_1)
EndFunc

Func startStuff()
    
    $win_3 = GUICreate("Doing something...",200,100,-1,-1,-1,-1,$win_2)
    $prog = GUICtrlCreateProgress(10,40,180,20)
    
    GUISetState(@SW_DISABLE,$win_2)
    GUISetState(@SW_SHOW,$win_3)
    GUISwitch($win_3)
    
    Local $t = TimerInit()
    Local $td = 0
    Do
        If $GUI_EVENT_CLOSE = GUIGetMsg() Then ExitLoop
        $td = TimerDiff($t)
        GUICtrlSetData($prog, $td / 200)
    Until $td > 20000
    
    GUISetState(@SW_ENABLE, $win_2)
    GUIDelete($win_3)
    GUISwitch($win_2)
EndFunc

Notice the GUISwitch() calls before the start and after the end of the GetMsg loops and $GUI_EVENT_CLOSE = GUIGetMsg() query inside of the worker loop (I also removed Sleep() call there to avoid GUI unresponsiveness).


UDFS & Apps:


DDEML.au3 - DDE Client + Server[*]
Localization.au3- localize your scripts[*]
TLI.au3 - type information on COM objects (TLBINF emulation)[*]
TLBAutoEnum.au3 - auto-import of COM constants (enums)[*]
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector

- OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ 

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  

×