Jump to content

Managing 2 GUIs - incorrect message handling


S0mbre
 Share

Recommended Posts

I implement 2 windows in my script: the main form ($gui) and a modal dialog ($gui2). To handle message processing, I use the advanced function GUIGetMsg(1) (as described in the Wiki article on managing multiple GUIs).

$gui2 is evoked by pressing a button on $gui. $gui is then disabled and the while loop should go through $gui2 until the 'close' message is received. Then $gui2 is deleted and $gui is re-enabled and activated. Everything, as you see, 'as the doctor prescribes'.

Everything was alright until I added a button to $gui2 (the dialog). When I did that, the message hadling routine continually received messages from this button even when $gui2 is not yet created! Can anyone explain to me how's that?

Here's my code.

Main form creation func:

Func GUI_Main()
    $gui = GUICreate("Перенос файлов", 400, 330)

    $lab_fromdir = GUICtrlCreateLabel("ИЗ    (папка):", 10, 5, 380)
    GUICtrlSetColor(-1, 0x0000ff)
    $edit_fromdir = GUICtrlCreateEdit(@DesktopDir, 10, 20, 355, 20, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL))
    $btn_browse_fromdir = GUICtrlCreateButton("...", 370, 20, 20, 20)

    $lab_todir = GUICtrlCreateLabel("В      (папка):", 10, 50, 380)
    GUICtrlSetColor(-1, 0x0000ff)
    $edit_todir = GUICtrlCreateEdit(@DesktopDir, 10, 65, 355, 20, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL))
    $btn_browse_todir = GUICtrlCreateButton("...", 370, 65, 20, 20)

    $lab_fname_mask = GUICtrlCreateLabel("Имя файла содержит (если любой файл - оставить пустым):", 10, 100, 380)
    GUICtrlSetColor(-1, 0x751E29)
    $edit_fname_mask = GUICtrlCreateEdit("", 10, 115, 380, 20, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL))
    GUICtrlSetBkColor(-1, 0xffff00)

    $lab_fext_mask = GUICtrlCreateLabel("Расширение файла, напр. ""mp3"" (если любое - оставить пустым):", 10, 140, 380)
    GUICtrlSetColor(-1, 0x751E29)
    $edit_fext_mask = GUICtrlCreateEdit("jpg", 10, 155, 380, 20, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL))
    GUICtrlSetBkColor(-1, 0xffff00)

    $btn_options = GUICtrlCreateButton("Опции...", 10, 180, 80, 25)

    $btn_start = GUICtrlCreateButton("Старт", 150, 235, 100, 30)

    $lab_prog = GUICtrlCreateLabel("Прогресс выполнения:", 10, 275, 140)
    GUICtrlSetColor(-1, 0xff0000)
    $lab_prog1 = GUICtrlCreateLabel("...", 150, 275, 240)
    GUICtrlSetColor(-1, 0x246B15)
    $pr_files = GUICtrlCreateProgress(10, 295, 380, 20, $PBS_SMOOTH)
    GUICtrlSetBkColor(-1, 0)
    GUICtrlSetColor(-1, 0x00ff00)
    GUICtrlSetData(-1, 0)
    GUICtrlSetState(-1, $GUI_SHOW)

    GUISetState()   
EndFunc

The dialog func:

Func GUI_Options()
    $gui2 = GUICreate("Опции", 400, 250, -1, -1, $DS_MODALFRAME)
    
    $btn_set = GUICtrlCreateButton("Сохранить", 10, 180, 80, 25) ; THAT'S THE BUTTON!!!
    
    $cb_movefiles = GUICtrlCreateCheckbox("Перенос файлов (если ВЫКЛ, будут копироваться)", 10, 10, 290, 20)  
    GUICtrlSetState(-1, $g_b_movefiles)
    $cb_overwrite = GUICtrlCreateCheckbox("Перезапись файлов (если ВЫКЛ, будут переименовываться)", 10, 30, 330, 20)
    GUICtrlSetState(-1, $g_b_overwrite)
            
    GUISetState(@SW_SHOW)
EndFunc

The code:

GUI_Main()

While True

    $msg = GUIGetMsg(1) ; ADVANCED MSG HANDLING
    switch $msg[1]
        
        Case $gui ; IF MAIN FORM
            msgbox(0, "", "FORM 1")
            switch $msg[0]
                Case $btn_browse_fromdir
                    ;                   
                Case $btn_browse_todir
                    ;               
                Case $btn_options
                    GUISetState(@SW_DISABLE, $gui) ; DISABLE THIS FORM
                    GUI_Options() ; EVOKE DIALOG
                                                                    
                Case $btn_start
                    ;
                
                Case $GUI_EVENT_CLOSE
                    ExitLoop
            EndSwitch
        
        Case $gui2 ; DIALOG FORM
            msgbox(0, "", "FORM 2")
            switch $msg[0]                  
                Case $btn_set
                    msgbox(0, "", "Message sent by BUTTON!") ; THIS MESSAGE KEEPS SHOWING UP!!!
                                            
                Case $GUI_EVENT_CLOSE                       
                    GUIDelete($gui2) ; DELETE THIS FORM
                    GUISetState(@SW_ENABLE, $gui) ; RE-ENABLE MAIN FORM
                    WinActivate($gui) ; ACTIVATE MAIN FORM
                    
            EndSwitch
        
    EndSwitch
    
WEnd

The script continually walks into Case $btn_set EVEN WHEN $gui2 IS YET TO BE CREATED!

Link to comment
Share on other sites

If there is no message, $msg[1] will be 0x00000000 and because you have not created the GUI yet, $gui2 will be 0. A similar match then occurs for the non existant button.

To stop this you could tell the script to continue if $msg[1] = 0 like this: (line 4 and 5)

While True
    $msg = GUIGetMsg(1) ; ADVANCED MSG HANDLING
    switch $msg[1]
        Case 0
            ContinueLoop ;don't do anything if there is no message.
        Case $gui ; IF MAIN FORM
            msgbox(0, "", "FORM 1")
            switch $msg[0]
                Case $btn_browse_fromdir
                    ;
                Case $btn_browse_todir
                    ;
                Case $btn_options
                    GUISetState(@SW_DISABLE, $gui) ; DISABLE THIS FORM
                    GUI_Options() ; EVOKE DIALOG
                Case $btn_start
                    ;
                Case $GUI_EVENT_CLOSE
                    ExitLoop
            EndSwitch
        Case $gui2 ; DIALOG FORM
            msgbox(0, "", "FORM 2")
            switch $msg[0]
                Case $btn_set
                    msgbox(0, "", "Message sent by BUTTON!") ; THIS MESSAGE KEEPS SHOWING UP!!!
                Case $GUI_EVENT_CLOSE
                    GUIDelete($gui2) ; DELETE THIS FORM
                    GUISetState(@SW_ENABLE, $gui) ; RE-ENABLE MAIN FORM
                    WinActivate($gui) ; ACTIVATE MAIN FORM
            EndSwitch
    EndSwitch
WEnd

Edit: removed my debug line.

Edited by Tvern
Link to comment
Share on other sites

My read on this is...

You had to pre-declare the $gui2 and $btn_set variables as a globals at the top of your source to avoid a compile error. So, prior to the creation of your child GUI, where $gui2 and $btn_set are assigned control ID's, they have a value of 0.

GUIGetMsg() returns a value of zero when no events have occured, so it mistakenly trips both your case tests for $gui2 and $btn_set.

Some options might be:

Put your switch statements inside "If Msg <> 0 Then" tests.

Use seperate GetMsg() control loops for each GUI.

Link to comment
Share on other sites

I did declare all the GUI variables ()as Global) before running the functions. Actually, I've found the solution to this problem by merely changing lines like

Case $gui_dlg
in the switch statement to the explicit
Case $msg[1] = $gui_dlg

I still don't get it why the first variant caused the problem...

Link to comment
Share on other sites

Read both our posts again. Spiff assumed you did declare the variables as global, simply because that's the only way the script will run.

The problem is that those variables are empty untill you put something in it and this evaluate as 0.

When there is no message GuiGetMsg returns 0x00000000, which also evaluates as 0.

You are then evaluating 0 = 0, which ofcoarse is True, meaning the cose associated with a button press is executed.

Your workaraound will work, but it creates confusing code and I think you are misunderstanding the way a Switch statement works. (no time to explain right now, maibe some other time)

The proper way to do it is by either:

Skipping the loop if there is no message, as shown in the previous examples. (mine should work with a simple cut and paste).

Declaring the Global variables with an initial value that will never match the value of GUIGetMsg. (I think -1 would work for instance)

Link to comment
Share on other sites

  • Moderators

S0mbre,

Reading the Managing Multiple GUIs tutorial in the Wiki might prove useful. :graduated:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Read both our posts again. Spiff assumed you did declare the variables as global, simply because that's the only way the script will run.

The problem is that those variables are empty untill you put something in it and this evaluate as 0.

When there is no message GuiGetMsg returns 0x00000000, which also evaluates as 0.

You are then evaluating 0 = 0, which ofcoarse is True, meaning the cose associated with a button press is executed.

Your workaraound will work, but it creates confusing code and I think you are misunderstanding the way a Switch statement works. (no time to explain right now, maibe some other time)

The proper way to do it is by either:

Skipping the loop if there is no message, as shown in the previous examples. (mine should work with a simple cut and paste).

Declaring the Global variables with an initial value that will never match the value of GUIGetMsg. (I think -1 would work for instance)

Actually, I did insert the "Case 0 ContinueLoop" statement and it worked fine, thank you! To reply to your conjecture that I don't understand the way Switch works, I am bound to return a negative answer: I do know that. I just didn't know that GuiGetMsg returns zero when there's no message.

Link to comment
Share on other sites

To reply to your conjecture that I don't understand the way Switch works, I am bound to return a negative answer: I do know that. I just didn't know that GuiGetMsg returns zero when there's no message.

Sorry about that, I was in a bit of a hurry when I wrote it.

What I meant was more along the lines of: Yes your solution works, but do you know why? When you write it out it gets a lot more complicated than it has to be and as such I would advise a different solution. (like the Case 0 solution)

I attempted to write out the steps of your solution to clarify why it works, but found it to be unconstructive at the time. Here's another try:

I will probably be corrected on parts of this, but this is sort of what happens.

#region in case of no message returned:
    Switch $msg[1]
        Case $msg[1] = $gui_dlg
    EndSwitch

    Switch 0x00000000 ;There is no handle
        Case 0x00000000 = 0 ;There is no value in $gui_dlg
    EndSwitch

    Switch False ;The empty handle translates to False
        Case True ;The empty handle is equal to the empty $gui_dlg
    EndSwitch
    ;obviously true isn't false, so the code doesn't run
#endregion

#region in case of a message returned by $gui_dlg:
    Switch 0x000F1D02
        Case 0x000F1D02 = 0x000F1D02
    EndSwitch

    Switch True ;the handle is something, so in a comparison to a boolean it will equate to True
        Case True ;The expression is True
    EndSwitch
    ;obviously True is True, so the code runs
#endregion
Link to comment
Share on other sites

Sorry about that, I was in a bit of a hurry when I wrote it.

What I meant was more along the lines of: Yes your solution works, but do you know why? When you write it out it gets a lot more complicated than it has to be and as such I would advise a different solution. (like the Case 0 solution)

I attempted to write out the steps of your solution to clarify why it works, but found it to be unconstructive at the time. Here's another try:

I will probably be corrected on parts of this, but this is sort of what happens.

#region in case of no message returned:
    Switch $msg[1]
        Case $msg[1] = $gui_dlg
    EndSwitch

    Switch 0x00000000 ;There is no handle
        Case 0x00000000 = 0 ;There is no value in $gui_dlg
    EndSwitch

    Switch False ;The empty handle translates to False
        Case True ;The empty handle is equal to the empty $gui_dlg
    EndSwitch
    ;obviously true isn't false, so the code doesn't run
#endregion

#region in case of a message returned by $gui_dlg:
    Switch 0x000F1D02
        Case 0x000F1D02 = 0x000F1D02
    EndSwitch

    Switch True ;the handle is something, so in a comparison to a boolean it will equate to True
        Case True ;The expression is True
    EndSwitch
    ;obviously True is True, so the code runs
#endregion

Thank you for this detailed reply. I think I understand now :graduated:
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...