Page 1 of 1

Manage main Window with child windows

Posted: Mon Jul 08, 2024 9:01 am
by tatanas
Hi,

I'm testing a multi-GUI program. In this example you will see a problem when opening "gui1", closing it, then opening "gui2"...
I need advice to handle this correctly. Should I reset gadget's variables to 0 when I close the "child" gui ?

Code: Select all

Global main_gui
Global button1, button2
Global gui1, gui2
Global buttonA, buttonB
Global buttonC, buttonD


Procedure open_gui1()
	gui1 = OpenWindow(#PB_Any, 100, 200, 195, 260, "Gui1 Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	buttonA = ButtonGadget(#PB_Any, 5, 5, 70, 22, "buttonA")
	buttonB = ButtonGadget(#PB_Any, 5, 35, 70, 22, "buttonB")
EndProcedure

Procedure open_gui2()
	gui2 = OpenWindow(#PB_Any, 100, 200, 195, 260, "Gui2 Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	buttonC = ButtonGadget(#PB_Any, 5, 5, 70, 22, "buttonC")
	buttonD = ButtonGadget(#PB_Any, 5, 35, 70, 22, "buttonD")
EndProcedure


main_gui = OpenWindow(#PB_Any, 100, 200, 195, 260, "Main Window", #PB_Window_SystemMenu)
If main_gui
	button1 = ButtonGadget(#PB_Any, 5, 5, 50, 22, "button1")
	button2 = ButtonGadget(#PB_Any, 5, 35, 50, 22, "button2")

	Repeat
		Event = WaitWindowEvent()

		Select Event
			Case #PB_Event_CloseWindow
				Select EventWindow()
					Case main_gui
						Quit = 1
	
					Case gui1
						Debug "close gui1"
						CloseWindow(gui1)
						
					Case gui2
						Debug "close gui2"
						CloseWindow(gui2)
				EndSelect

			Case #PB_Event_Gadget
				Select EventGadget()
					Case button1
						open_gui1()

					Case button2
						open_gui2()

					Case buttonA
						Debug "buttonA"
					Case buttonB
						Debug "buttonB"						
					Case buttonC
						Debug "buttonC"						
					Case buttonD
						Debug "buttonD"
						
				EndSelect
		EndSelect
		
	Until Quit = 1
	
EndIf
Thanks for your time.

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 9:24 am
by infratec
The problem is that the Window handle is 'reused":
gui1 44235816
close gui1
gui2 44235816
close gui1
You should use enumeration constants instead of #PB_Any then it works as expected.

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 9:30 am
by infratec

Code: Select all

EnableExplicit

Enumeration window
  #MainWindow
  #Gui1Window
  #Gui2Window
EndEnumeration

Enumeration Gadget
  #Button1
  #Button2
  #ButtonA
  #ButtonB
  #ButtonC
  #ButtonD
EndEnumeration



Procedure open_gui1()
  OpenWindow(#Gui1Window, 100, 200, 195, 260, "Gui1 Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Debug "gui1 " + Str(#Gui1Window)
	ButtonGadget(#ButtonA, 5, 5, 70, 22, "buttonA")
	ButtonGadget(#ButtonB, 5, 35, 70, 22, "buttonB")
EndProcedure

Procedure open_gui2()
  OpenWindow(#Gui2Window, 100, 200, 195, 260, "Gui2 Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Debug "gui2 " + Str(#Gui2Window)
	ButtonGadget(#ButtonC, 5, 5, 70, 22, "buttonC")
	ButtonGadget(#ButtonD, 5, 35, 70, 22, "buttonD")
EndProcedure


Define Event.i, Quit.i


If OpenWindow(#MainWindow, 100, 200, 195, 260, "Main Window", #PB_Window_SystemMenu)
	ButtonGadget(#Button1, 5, 5, 50, 22, "button1")
	ButtonGadget(#Button2, 5, 35, 50, 22, "button2")

	Repeat
		Event = WaitWindowEvent()

		Select Event
			Case #PB_Event_CloseWindow
				Select EventWindow()
					Case #MainWindow
						Quit = 1
	
					Case #Gui1Window
						Debug "close gui1"
						CloseWindow(#Gui1Window)
						
					Case #Gui2Window
						Debug "close gui2"
						CloseWindow(#Gui2Window)
				EndSelect

			Case #PB_Event_Gadget
				Select EventGadget()
					Case #button1
						open_gui1()

					Case #button2
						open_gui2()

					Case #buttonA
						Debug "buttonA"
					Case #buttonB
						Debug "buttonB"						
					Case #buttonC
						Debug "buttonC"						
					Case #buttonD
						Debug "buttonD"
						
				EndSelect
		EndSelect
		
	Until Quit = 1
	
EndIf

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 10:32 am
by tatanas
infratec, I tested your sample and got a problem when I open/close multiple times.
the debug log :

Code: Select all

gui1 1
buttonA
buttonB
close gui1
gui2 2
buttonC
buttonD
close gui2
gui1 1
buttonA
buttonB
close gui1
gui2 2
buttonA    <---- should be buttonC
buttonB    <---- should be buttonD
close gui2

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 10:42 am
by spikey
tatanas wrote: Mon Jul 08, 2024 9:01 am Should I reset gadget's variables to 0 when I close the "child" gui ?
Yes, the window variable too. As you've discovered, and Infratec observed, numbers in the #PB_Any ranges will be re-used if they are available. You need to ensure that your variables reflect this state too. Otherwise you can get undesirable responses or even a runtime crash if you try to reference an object which doesn't exist any more.
infratec wrote: Mon Jul 08, 2024 9:24 am You should use enumeration constants instead of #PB_Any then it works as expected.
This is not necessary, see below. There's another problem with this code though. If you click 'Button1' or 'Button2' twice consecutively without closing the window in between, you will end up with an orphan window over which there is no longer any control. I suggest one solution for this below too:

Code: Select all

Global main_gui
Global button1, button2
Global gui1, gui2
Global buttonA, buttonB
Global buttonC, buttonD


Procedure open_gui1()
  gui1 = OpenWindow(#PB_Any, 100, 200, 195, 260, "Gui1 Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  buttonA = ButtonGadget(#PB_Any, 5, 5, 70, 22, "buttonA")
  buttonB = ButtonGadget(#PB_Any, 5, 35, 70, 22, "buttonB")
EndProcedure

Procedure open_gui2()
  gui2 = OpenWindow(#PB_Any, 100, 200, 195, 260, "Gui2 Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  buttonC = ButtonGadget(#PB_Any, 5, 5, 70, 22, "buttonC")
  buttonD = ButtonGadget(#PB_Any, 5, 35, 70, 22, "buttonD")
EndProcedure


main_gui = OpenWindow(#PB_Any, 100, 200, 195, 260, "Main Window", #PB_Window_SystemMenu)
If main_gui
  button1 = ButtonGadget(#PB_Any, 5, 5, 50, 22, "button1")
  button2 = ButtonGadget(#PB_Any, 5, 35, 50, 22, "button2")
  
  Repeat
    Event = WaitWindowEvent()
    
    Select Event
      Case #PB_Event_CloseWindow
        Select EventWindow()
          Case main_gui
            Quit = 1
            
          Case gui1
            Debug "close gui1"
            CloseWindow(gui1)
            gui1 = 0
            buttonA = 0
            buttonB = 0
            
          Case gui2
            Debug "close gui2"
            CloseWindow(gui2)
            gui2 = 0
            buttonC = 0
            buttonD = 0
            
        EndSelect
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case button1
            If IsWindow(gui1)
              SetActiveWindow(gui1)
            Else
              open_gui1()
            EndIf 
            
          Case button2
            If IsWindow(gui2)
              SetActiveWindow(gui2)
            Else
              open_gui2()
            EndIf
            
          Case buttonA
            Debug "buttonA"
          Case buttonB
            Debug "buttonB"						
          Case buttonC
            Debug "buttonC"						
          Case buttonD
            Debug "buttonD"
            
        EndSelect
    EndSelect
    
  Until Quit = 1
  
EndIf

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 11:08 am
by infratec
The same problem:

The numbers are reused if you free the gadgets (done when closing the window).

I personally use only #PB_Any when I have to create one window type multiple times in parallel.
For example wehn it is allowed to edit multiple records of a database at the same time.

The overhead for the varible handling is simply to big.

I modified my listing above.

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 1:47 pm
by tatanas
Thank you everyone
So there are 2 possibilities : reset global gadgets and windows variables to 0 or use enumeration constants.

Re: Manage main Window with child windows

Posted: Mon Jul 08, 2024 2:04 pm
by #NULL
In case you would mix constant IDs with dynamic ones, which is absolutely possible, more is needed.
If a window with constant 0 exists, then IsWindow(variable) returns true if variable is 0. So either use -1 for your dynamic default state, or check like var<>0 (and/or var <> -1) instead of using Is..() functions directly on the variable.