Page 1 of 2

How do I create a main loop for Multiple-Forms?

Posted: Thu Dec 21, 2006 5:37 pm
by Noble Bell
Hello all,

I guess I have been in hiding for awhile. Yikes, some things have changed. :D

Here is my question(s):

1) I tried to contact the folks at PureVision via an email. Never heard anything back. Are they still around and do you know if their latest version will produce the latest version of PB code? I am thinking of purchasing it in the very near future.

The big question that has been troubling me lately is this:

I have been writing some applications that only require single forms and now I have the need to develop an app that has 10 forms in it.

What is the best way to code the main message loop to handle all the forms?

I have one main form and the rest of the forms are forms that get called from the main form. (Note: I am NOT doing a MDI format I am using a single document interface.)

Ie. I want the main form to be present all the time but when you call a form from the main form I just want the main form to move to the background (loose focus) and make the just opened form the one to have focus.

Thanks for your help and Merry Christmas to all.

Ps. I'll try not to stay hidden so long in the future. :wink:

nb

Posted: Thu Dec 21, 2006 5:51 pm
by netmaestro
See the tutorials and examples here:

http://www.xs4all.nl/~bluez/datatalk/purebasic.htm

Posted: Thu Dec 21, 2006 5:55 pm
by Kaeru Gaman
> What is the best way to code the main message loop to handle all the forms?

use one mainloop and one WaitWindowEvent(),
but branche immediately after that in seperate sub-parts of the code by using EventWindow()

> Ie. I want the main form to be present all the time but when you call a form from the main form I just want the main form to move to the background (loose focus) and make the just opened form the one to have focus.

when you call OpenWindow(...), a new Form will open and will have the Focus.

the focus will change the normal way when you click on other windows, OS will handle this.

if you need special control about this, you can make use of GetActiveWindow() / SetActiveWindow(), but its not necessary for normal event when you use EventWindow() as a main-branch

don't end your mainloop with
Until EventID = #PB_Event_CloseWindow

check the seperate ExitButtons within the branch, and only exit your mainloop if it was the exitbutton of your mainwindow.

Posted: Thu Dec 21, 2006 6:09 pm
by Noble Bell
Great information. Thanks!
That is what I was looking for.

Posted: Fri Dec 22, 2006 3:59 am
by NoahPhense
Maybe a small example with three windows would be nice.

- np

Posted: Fri Dec 22, 2006 4:44 am
by Noble Bell
Yes, that would be excellent.

Posted: Fri Dec 22, 2006 7:22 am
by Tranquil
I always use DisableWindow() and HideWindow() to show my desired forms. But it depends on your needs. Sometimes I need two active windows, so I also need to handle these two window-events in one loop.
But the normal behavior is to check one window for events.

GUI controls (Gadgets) & Windows are always global in my projects.

Code: Select all

Global wnd_main    = OpenWindow(#PB_Any,0,0,200,200,"Main Form",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(WND_Main))
Global BTN_Main_Form1  = ButtonGadget(#PB_Any,10,10,100,20,"Go to Form 1")
Global BTN_Main_Form2  = ButtonGadget(#PB_Any,10,30,100,20,"Go to Form 2")
Global BTN_Main_Form3  = ButtonGadget(#PB_Any,10,70,100,20,"Go to Form 3")

Global wnd_form1   = OpenWindow(#PB_Any,0,0,200,200,"Form 1",#PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Invisible)

Global wnd_form2   = OpenWindow(#PB_Any,0,0,200,200,"Form 2",#PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Invisible)

Global wnd_form3   = OpenWindow(#PB_Any,0,0,200,200,"Form 3",#PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Invisible)


Procedure Form1()
  HideWindow(WND_form1,0)
  
  Repeat
    ; Process your form 1 events here
  
  Until WaitWindowEvent() = #PB_Event_CloseWindow
  HideWindow(WND_form1,1)
EndProcedure

Procedure Form2()
  HideWindow(WND_form2,0)
  
  Repeat
    ; Process your form 2 events here
  
  Until WaitWindowEvent() = #PB_Event_CloseWindow
  HideWindow(WND_form2,1)
EndProcedure

Procedure Form3()
  HideWindow(WND_form3,0)
  
  Repeat
    ; Process your form 3 events here
  
  Until WaitWindowEvent() = #PB_Event_CloseWindow
  HideWindow(WND_form3,1)
EndProcedure


Repeat
  
  Event.l     = WaitWindowEvent()
  Gadget.l    = EventGadget()
  
  Select Event
    Case #PB_Event_Gadget
    
      If Gadget = BTN_Main_Form1
        DisableWindow(WND_Main,1)
        Form1()
        DisableWindow(WND_Main,0)
        SetActiveWindow(WND_Main)
      EndIf
  
      If Gadget = BTN_Main_Form2
        DisableWindow(WND_Main,1)
        Form2()
        DisableWindow(WND_Main,0)
        SetActiveWindow(WND_Main)
      EndIf
  
      If Gadget = BTN_Main_Form3
        DisableWindow(WND_Main,1)
        Form3()
        DisableWindow(WND_Main,0)
        SetActiveWindow(WND_Main)
      EndIf
  
  EndSelect

Until event.l = #PB_Event_CloseWindow

End

Re: How do I create a main loop for Multiple-Forms?

Posted: Fri Dec 22, 2006 8:37 am
by PB
> I tried to contact the folks at PureVision via an email. Never heard
> anything back. Are they still around and do you know if their latest
> version will produce the latest version of PB code?

Paul still posts here now and again, so you'd need to PM him. Don't know
about the latest version of PureVision but maybe try asking in that forum
on his website? Surely he'd reply there if it's still supported?

Re: How do I create a main loop for Multiple-Forms?

Posted: Fri Dec 22, 2006 4:58 pm
by NoahPhense
Here's another from another thread:

No need for globals, and doesn't lock down the application.

Run with debugger mode.

Code: Select all

OpenWindow(1, 0, 0, 230, 90, "Event handling example...1", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 

   If CreateGadgetList(WindowID(1)) 
     ButtonGadget  (1, 10, 10, 200, 20, "Click me") 
     CheckBoxGadget(2, 10, 40, 200, 20, "Check me") 
   EndIf 

   If CreateMenu(1, WindowID(1)) 
     MenuTitle("Menu") 
     MenuItem(1, "Item 1") 
     MenuItem(2, "Item 2") 
     MenuItem(3, "Item 3") 
   EndIf 

OpenWindow(2, 0, 0, 230, 90, "Event handling example...2", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 

   If CreateGadgetList(WindowID(2)) 
     ButtonGadget  (3, 10, 10, 200, 20, "Click me") 
     CheckBoxGadget(4, 10, 40, 200, 20, "Check me") 
   EndIf 

   If CreateMenu(2, WindowID(2)) 
     MenuTitle("Menu") 
     MenuItem(4, "Item 1") 
     MenuItem(5, "Item 2") 
     MenuItem(6, "Item 3") 
   EndIf 

Repeat 
 Event = WaitWindowEvent() 
 Window = EventWindow() 
 Gadget = EventGadget() 
 Menu = EventMenu() 
 Select Window 
   Case 1 
     Select Event 
       Case #PB_Event_Gadget 
         Select Gadget 
           Case 1 : Debug "Win1 Button 1 clicked!" 
           Case 2 : Debug "Win1 Button 2 clicked!" 
         EndSelect 
       Case #PB_Event_Menu 
         Select Menu 
           Case 1 : Debug "Win1 Menu item 1 clicked!" 
           Case 2 : Debug "Win1 Menu item 2 clicked!" 
           Case 3 : Debug "Win1 Menu item 3 clicked!" 
         EndSelect 
       Case #PB_Event_CloseWindow 
         End 
     EndSelect 
   Case 2 
    Select Event 
       Case #PB_Event_Gadget 
         Select Gadget 
           Case 3 : Debug "Win2 Button 1 clicked!" 
           Case 4 : Debug "Win2 Button 2 clicked!" 
         EndSelect 
       Case #PB_Event_Menu 
         Select Menu 
           Case 4 : Debug "Win2 Menu item 1 clicked!" 
           Case 5 : Debug "Win2 Menu item 2 clicked!" 
           Case 6 : Debug "Win2 Menu item 3 clicked!" 
         EndSelect 
       Case #PB_Event_CloseWindow 
         End 
     EndSelect 
 EndSelect 

Until Event = #PB_Event_CloseWindow
Finds which window by:
Select Window
Case 1


- np

Posted: Fri Dec 22, 2006 5:01 pm
by netmaestro

Code: Select all

;========================================================
; Program:  Multiple Window Object/Event Management
; Author:   netmaestro
; Date:     December 22, 2006
;           Feel free to suggest improvements
;========================================================

; Main Window 
Enumeration
  #wMain
  ; Menus & Items
  #wMain_Menu
    #wMain_Menu_Item_Open1
    #wMain_Menu_Item_Open2
    #wMain_Menu_Item_Exit    
  ; Gadgets
  #wMain_Text1
EndEnumeration

; Window One
Enumeration 100
  #wOne
  #wOne_Txt_Text1
  #wOne_Btn_Button1
EndEnumeration

; Window Two
Enumeration 200
  #wTwo
  #wTwo_Txt_Text1
  #wTwo_Btn_Button1
EndEnumeration

Procedure OpenWindowMain()
  flags = #PB_Window_ScreenCentered|#PB_Window_SystemMenu
  If OpenWindow(#wMain,0,0,320,240,"Main Window",flags) And  CreateGadgetList(WindowID(#wMain))
    TextGadget(#wMain_Text1,100,100,200,20,"Main Window")
    If CreateMenu(#wMain_Menu, WindowID(#wMain))
      MenuTitle("File")
      MenuItem(#wMain_Menu_Item_Open1, "Open Window One")
      MenuItem(#wMain_Menu_Item_Open2, "Open Window Two")   
      MenuItem(#wMain_Menu_Item_Exit, "Exit")
      ProcedureReturn WindowID(#wMain)
    Else
      ProcedureReturn 0
    EndIf
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure OpenWindowOne()
  flags = #PB_Window_SystemMenu
  left  = WindowX(#wMain)-328
  top   = WindowY(#wMain)+25
  If OpenWindow(#wOne,left,top,320,240,"Window One",flags) And CreateGadgetList(WindowID(#wOne))
    TextGadget(#wOne_Txt_Text1,120,100,200,20,"Window One")
    ButtonGadget(#wOne_Btn_Button1,120,140,60,20,"Say Hi")
    UseGadgetList(WindowID(#wMain))
    DisableMenuItem(#wMain_Menu, #wMain_Menu_Item_Open1, #True)
    ProcedureReturn WindowID(#wOne)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure OpenWindowTwo()
  flags = #PB_Window_SystemMenu
  left  = WindowX(#wMain)+328
  top   = WindowY(#wMain)+25
  If OpenWindow(#wTwo,left,top,320,240,"Window Two",flags) And CreateGadgetList(WindowID(#wTwo))
    TextGadget(#wTwo_Txt_Text1,120,100,200,20,"Window Two")
    ButtonGadget(#wTwo_Btn_Button1,120,140,60,20,"Say Hi")
    UseGadgetList(WindowID(#wMain))
    DisableMenuItem(#wMain_Menu, #wMain_Menu_Item_Open2, #True)
    ProcedureReturn WindowID(#wTwo)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure WindowMainEvents(event)
  Protected running = #True
  Select event
    Case #PB_Event_CloseWindow
      running = #False
    Case #PB_Event_Menu
      Select EventMenu()
        Case #wMain_Menu_Item_Open1
          If Not OpenWindowOne()
            MessageRequester("Error", "Unable to open Window One", #MB_ICONERROR)
          EndIf
        Case #wMain_Menu_Item_Open2
          If Not OpenWindowTwo()
            MessageRequester("Error", "Unable to open Window Two", #MB_ICONERROR)
          EndIf        
        Case #wMain_Menu_Item_Exit
          running = #False
      EndSelect
  EndSelect
  ProcedureReturn running
EndProcedure

Procedure WindowOneEvents(event)
  Select event
    Case #PB_Event_CloseWindow
      CloseWindow(#wOne)
      DisableMenuItem(#wMain_Menu, #wMain_Menu_Item_Open1, #False)
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #wOne_Btn_Button1
          MessageRequester("Notice","Hello from Window One!",#MB_ICONINFORMATION)
      EndSelect
  EndSelect
EndProcedure

Procedure WindowTwoEvents(event)
  Select event
    Case #PB_Event_CloseWindow
      CloseWindow(#wTwo)
      DisableMenuItem(#wMain_Menu, #wMain_Menu_Item_Open2, #False)
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #wTwo_Btn_Button1
          MessageRequester("Notice","Hello from Window Two!",#MB_ICONINFORMATION)
      EndSelect
  EndSelect
EndProcedure

;========================================
;       Main Loop ...clean, eh? ;-) 
;========================================

If OpenWindowMain()

  runstatus = #True
  Repeat
  
    EventID = WaitWindowEvent()

    Select EventWindow()

      Case #wMain
        runstatus = WindowMainEvents(EventID)

      Case #wOne
        WindowOneEvents(EventID)

      Case #wTwo
        WindowTwoEvents(EventID)
        
    EndSelect
    
  Until runstatus = #False
  
EndIf


Posted: Fri Dec 22, 2006 5:07 pm
by Kaeru Gaman
But the normal behavior is to check one window for events.
the normal way would be to use an OOP-Language for an OO-Surface.

there is no need to activate/disable your windows,
but it can be easier to handle sometimes.

alternatively you can use threads to handle different windows.
each window can have an own event-loop withing its thread.
for such, the communication between windows has to be handled through Globals,
you can't SetGadgetText on a Gadget of a different thread.

but it's not that difficult to handle multiple windows in one event-loop.
I coded a little example, hope I eliminated every bug and typo.
tested it more than once, should be ready.
(ok, a few minutes late, but i coded it for this topic so i will post it. ;) )

please note that each Gadget needs a unique number.
if you try to put a Button No.9 on Window1, and later a
Textgadget No. 9 on Window 2, the Button will vanish.
so you'l need one single Enum for the Gadgets.
Also keep in mind to use seperate Enums for Windows and Gadgets,
because both lists should start with No.0 and continue without Gaps.
enumerating with other start-numbers or with gaps will cause no Error
but may lower Performance.

of course you don't really need to devide the code into window-cases first.
you could check all the gadgets within the same code-section,
just because they all have unique numbers.
but also then you should at least seperate them by thick remarks,
and you will need to write a second section that is devided into
window-cases for non-gadget-events like CloseWindow.

in my opinion it's best readable if its clealy devided into sections by
Window-Number, each section handling every event for this window.
[edit]
netmeastro achieved this by using seperate procedures. :)
[/edit]

questions/suggestions/critics welcome

Code: Select all

;*********************************************************
;*** MoreWindows.pb
;***
;*** Example for use of EventWindow()
;*** to handle multiple Windows
;*** without child/parent
;***
;*** Dec.22, 2006  Kaeru Gaman
;***
;*** PB Ver 4.02 Win
;*********************************************************
EnableExplicit
;*************************************
Enumeration     ;Windows
  #Win_Main
  #Win_Sub1
  #Win_Sub2
  #Win_Sub3
  #Win_Sub4
EndEnumeration
;*************************************
Enumeration     ;Gadgets
  #Main_But_LaunchSub1
  #Main_But_LaunchSub2
  #Main_But_LaunchSub3
  #Main_Txt_Display
  #Sub1_But_TestBeep  
  #Sub2_But_TestBeep  
  #Sub3_But_LaunchSub4
  #Sub4_Opt_Text1
  #Sub4_Opt_Text2
  #Sub4_Opt_Text3
EndEnumeration
;*************************************
 Procedure OpenSub1()
  OpenWindow(#Win_Sub1, -1, -1, 200,150,"Sub1",#PB_Window_ScreenCentered | #PB_Window_SystemMenu )
    CreateGadgetList(WindowID(1))
      ButtonGadget(#Sub1_But_TestBeep,10,10,60,20,"Beep Deep")
 EndProcedure
;*************************************
 Procedure OpenSub2()
  OpenWindow(#Win_Sub2, -1, -1, 200,150,"Sub2",#PB_Window_ScreenCentered | #PB_Window_SystemMenu )
    CreateGadgetList(WindowID(2))
      ButtonGadget(#Sub2_But_TestBeep,10,10,60,20,"Beep High")
 EndProcedure
;*************************************
 Procedure OpenSub3()
  OpenWindow(#Win_Sub3, -1, -1, 200,150,"Sub3",#PB_Window_ScreenCentered | #PB_Window_SystemMenu )
    CreateGadgetList(WindowID(3))
    ButtonGadget(#Sub3_But_LaunchSub4, 70,110,120,30,"Launch Sub4")
 EndProcedure
;*************************************
 Procedure OpenSub4()
  OpenWindow(#Win_Sub4, -1, -1, 200,150,"Sub4",#PB_Window_ScreenCentered | #PB_Window_SystemMenu )
    CreateGadgetList(WindowID(4))
      OptionGadget(#Sub4_Opt_Text1,20,20,160,20,"Beef")
      OptionGadget(#Sub4_Opt_Text2,20,50,160,20,"Lamb")
      OptionGadget(#Sub4_Opt_Text3,20,80,160,20,"Fish")
 EndProcedure
;*************************************
OpenWindow(#Win_Main,0,0,320,240,"Main", #PB_Window_ScreenCentered | #PB_Window_SystemMenu )
  CreateGadgetList(WindowID(0))
    ButtonGadget(#Main_But_LaunchSub1,190,120,120,30,"Launch Sub1")
    ButtonGadget(#Main_But_LaunchSub2,190,160,120,30,"Launch Sub2")
    ButtonGadget(#Main_But_LaunchSub3,190,200,120,30,"Launch Sub3")
    TextGadget(#Main_Txt_Display,10,10,160,20, "No Choice yet", #PB_Text_Border)
;*************************************
Define Event.l
Define EXIT.l
Define DisplayTxt$ = "Your Choice is "
;*************************************
Repeat
  Event = WaitWindowEvent()
  Select EventWindow()
;*********************************************************
;*** Main Window
;*********************************************************
    Case   #Win_Main
      Select Event
        Case #PB_Event_Gadget
    ;*************************************
    ;** Gadget Events
          Select EventGadget()
            Case #Main_But_LaunchSub1
              OpenSub1()
            Case #Main_But_LaunchSub2
              OpenSub2()
            Case #Main_But_LaunchSub3
              OpenSub3()
          EndSelect
    ;*************************************
    ;** Other Events
        Case #PB_Event_CloseWindow
          EXIT = 1
      EndSelect
;*********************************************************
;*** Sub Window 1
;*********************************************************
    Case #Win_Sub1
      Select Event
        Case #PB_Event_Gadget
    ;*************************************
    ;** Gadget Events
          Select EventGadget()
            Case #Sub1_But_TestBeep
              Beep_( 500,300)
          EndSelect
    ;*************************************
    ;** Other Events
        Case #PB_Event_CloseWindow
          CloseWindow(#Win_Sub1)
      EndSelect
;*********************************************************
;*** Sub Window 2
;*********************************************************
    Case #Win_Sub2
      Select Event
        Case #PB_Event_Gadget
    ;*************************************
    ;** Gadget Events
          Select EventGadget()
            Case #Sub2_But_TestBeep
              Beep_(1500,300)
          EndSelect
    ;*************************************
    ;** Other Events
        Case #PB_Event_CloseWindow
          CloseWindow(#Win_Sub2)
      EndSelect
;*********************************************************
;*** Sub Window 3
;*********************************************************
    Case #Win_Sub3
      Select Event
        Case #PB_Event_Gadget
    ;*************************************
    ;** Gadget Events
          Select EventGadget()
            Case #Sub3_But_LaunchSub4
              OpenSub4()
          EndSelect
    ;*************************************
    ;** Other Events
        Case #PB_Event_CloseWindow
          CloseWindow(#Win_Sub3)
      EndSelect
;*********************************************************
;*** Sub Window 4
;*********************************************************
    Case #Win_Sub4
      Select Event
        Case #PB_Event_Gadget
    ;*************************************
    ;** Gadget Events
          Select EventGadget()
            Case #Sub4_Opt_Text1
              SetGadgetText(#Main_Txt_Display, DisplayTxt$ + "Beef")
            Case #Sub4_Opt_Text2
              SetGadgetText(#Main_Txt_Display, DisplayTxt$ + "Lamb")
            Case #Sub4_Opt_Text3
              SetGadgetText(#Main_Txt_Display, DisplayTxt$ + "Fish")
          EndSelect
    ;*************************************
    ;** Other Events
        Case #PB_Event_CloseWindow
          CloseWindow(#Win_Sub4)
      EndSelect
;*********************************************************
;*** End of Window List
;*********************************************************
  EndSelect
Until EXIT = 1
End

Posted: Fri Dec 22, 2006 5:14 pm
by NoahPhense
netm .. freakin sweet..

- np

Posted: Fri Dec 22, 2006 5:26 pm
by ts-soft
@netmaestro
this:

Code: Select all

; Window One
Enumeration 100
  #wOne
  #wOne_Txt_Text1
  #wOne_Btn_Button1
EndEnumeration

; Window Two
Enumeration 200
  #wTwo
  #wTwo_Txt_Text1
  #wTwo_Btn_Button1
EndEnumeration
use mem for 204 Gadgets in the GadgetList :wink:
better this:

Code: Select all

Enumeration ;Window One
  #wOne
  #wOne_Txt_Text1
  #wOne_Btn_Button1
EndEnumeration

Enumeration #PB_Compiler_EnumerationValue ; Window Two
  #wTwo
  #wTwo_Txt_Text1
  #wTwo_Btn_Button1
EndEnumeration

Posted: Fri Dec 22, 2006 5:30 pm
by netmaestro
Good point, I mainly did it that way for debugging purposes. If I test EventGadget() or GetDlgCtrlID_() with debugging tools and find 203 I know which window it's for. But I didn't remember that it would use more memory... :oops:

Posted: Fri Dec 22, 2006 5:50 pm
by netmaestro
Wait a minute, ts, are you sure of that? I ran the code with #PB_Compiler_EnumerationValue and the CPU Monitor said I'm using 2.54 mb. I changed the Window Two enumeration to Enumeration 9000 and ran that - CPU monitor said 2.54 mb used by the program. Surely if I were allocating space for 9000 gadgets I'd see at least some increase in memory used.. -right?