Page 1 of 1

beginners: event loop framework

Posted: Sat Dec 31, 2005 7:48 am
by blueznl
Code updated For 5.20+

(first example is 3.94, if you scroll down you'll find the 4.00 b5 version)

i noticed that there were still some questions about handling mutliple windows, each with their own events, gadgets, messages etc. so here's a sample mainloop for starters, it's perhaps an alternative way to turn events into actions...

Code: Select all

; purebasic survival guide - pb3.94
; mainloop_1.pb - 30.12.2005 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/purebasic.htm
;
; - basic framework
; - menus
; - event loop
; - gadgets
; - multi window handling
; - gadget and window resizing
;

Declare init()
Declare main()
init()
main()

Procedure init()
  ;
  ; *** all global declarations, enumeration stuff etc. ***
  ;
  ; enumeration is your best friend... i use it here to identify...
  ; - all functions of the program (actions taken)
  ; - all windows
  ; - all menus
  ; - all gadgets
  ;
  Enumeration
    ;
    ; functions - either real menu entries or logical functions
    ;
    #f_exit
    #f_show_child
    #f_close_child
    #f_toggle_child
    ;
    ; windows
    ;
    #w_main_nr
    #w_child_nr
    ;
    ; menus
    ;
    #m_main_nr
    ;
    ; gadgets main
    ;
    #g_main_exit
    #g_main_sample_listview
    #g_main_toggle_child
    ;
    ; gadgets child
    ;
    #g_child_close
    ;
  EndEnumeration
  ;
  ; add other global stuff
  ;
EndProcedure

Procedure reflect_settings()
  Global show_child
  ;
  ; *** show current settings in gadgets ***
  ;
  SetMenuItemState(#m_main_nr,#f_toggle_child,show_child)
  ;
EndProcedure

Procedure draw()
  Protected w, h
  Global w_main_h, w_child_h, show_child
  ;
  ; *** all draw, redraw, and resize routines ***
  ;
  ; this is the main drawing procedure, all setting up of windows, creation of gadgets
  ; and so on take place in here, this is also the place where you could store resizing
  ; code, this procedure does not update the status of gadgets or menus, for that
  ; reflect_settings() has to be called seperately
  ;
  ;
  ; *** main window ***
  ;
  If IsWindow(#w_main_nr)                        ; redraw or resize
    ;
    ;         UseWindow()
    w = WindowWidth(#w_main_nr)
    h = WindowHeight(#w_main_nr)
    h = h-MenuHeight()-32
    ResizeGadget(#g_main_sample_listview,2,2,w-4,h-4)
    ResizeGadget(#g_main_toggle_child,2,h+4,w-4,24)
    ;
  Else                                           ; create the window
    ;
    w = 400
    h = 400
    w_main_h = OpenWindow(#w_main_nr,10,10,400,400,"Primary",#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
    ;
    CreateMenu(#m_main_nr,w_main_h)
    MenuTitle("&File")
    MenuItem(#f_show_child,"&Show child")
    MenuItem(#f_close_child,"&Close child")
    MenuItem(#f_toggle_child,"&Toggle child")
    MenuBar()
    MenuItem(#f_exit,"E&xit")
    ;
    h = h-MenuHeight()-32
    
    ListViewGadget(#g_main_sample_listview,2,2,w-4,h-4)
    ButtonGadget(#g_main_toggle_child,2,h+4,w-4,24,"Toggle child")
    ;
  EndIf
  ;
  ; *** child window ***
  ;
  ; showing all other windows would depend on the value of the associated flags / variables
  ;
  If show_child = #True                          ; we want a window
    If IsWindow(#w_child_nr)                     ; window already exists, redraw or resize
      ;
    Else                                         ; create the window
      ;
      w_child_h = OpenWindow(#w_child_nr,10,10,110,110,"Childwindow",#PB_Window_SystemMenu|#PB_Window_ScreenCentered,w_main_h)
      
      ButtonGadget(#g_child_close,2,2,108,108,"Close")
      ;
    EndIf
  Else                                           ; we donn't want a window
    If IsWindow(#w_child_nr)                     ; exists so close the window
      CloseWindow(#w_child_nr)
    Else                                         ; doesn't exist so don't bother
    EndIf
  EndIf
  ;
  ; repeat the above for any other window / gadget
  ;
EndProcedure

Procedure main_loop()
  Global event, event_gadget, event_window, event_menu, show_child
  ;
  draw()
  ;
  Repeat
    action = -1
    ;
    event = WaitWindowEvent()
    event_type = EventType()
    event_menu = EventMenu()
    event_window = EventWindow()
    event_gadget = EventGadget()
    ;
    ; i've set this up as following:
    ;
    ; 1. grab all events
    ; 2. process them per window
    ;    - first menu events
    ;    - then window events
    ;    - then gadgets
    ; 3. events either cause immediate actions, or they set the variable 'action'
    ;    (this allows me to have different events / gadgets / menu's to do the same thing)
    ; 4. if the action variable is non-zero it may cause certain actions as well
    ;
    Select event_window
      Case #w_main_nr
        ;
        ; process all events caused by the main window
        ;
        Select event
          Case #PB_Event_Menu
            action = event_menu
          Case #PB_Event_CloseWindow
            action = #f_exit
          Case #PB_Event_SizeWindow
            draw()
          Case #PB_Event_Gadget
            ;
            ; process all events caused by gadgets in the main window
            ;
            Select event_gadget
              Case #g_main_toggle_child
                action = #f_toggle_child
              Case #g_main_exit
                action = #f_exit
              Default
            EndSelect
            ;
          Default
        EndSelect
        ;
      Case #w_child_nr
        ;
        ; process all events caused by the child window
        ;
        Select event
          Case #PB_Event_Menu
            action = event_menu
          Case #PB_Event_CloseWindow
            action = #f_close_child
          Case #PB_Event_Gadget
            ;
            ; process all events caused by gadgets in the child window
            ;
            Select event_gadget
              Case #g_child_close
                action = #f_close_child
              Default
            EndSelect
            ;
          Default
        EndSelect
        ;
    EndSelect
    ;
    ;
    ; *** action section ***
    ;
    ; events either immediately take action (in the block above) or they
    ; set the action variable causing an action below
    ;
    Select action
      Case #f_show_child
        show_child = #True
        draw()
        reflect_settings()
      Case #f_close_child
        show_child = #False
        draw()
        reflect_settings()
      Case #f_toggle_child
        If show_child = #True
          show_child = #False
        Else
          show_child = #True
        EndIf
        draw()
        reflect_settings()
    EndSelect
    ;
  Until action = #f_exit
  ;
EndProcedure

Procedure main()
  Protected command.s
  ;
  ; in complex programs that support gui as well as command line functions i tend to
  ; seperate these two in two different sections
  ;
  command = ProgramParameter()
  Select command
    Case ""
      main_loop()
      ;
    Case "debug"
      MessageRequester("Command","Debug...",#PB_MessageRequester_Ok)
      ;
    Default
      MessageRequester("Command","Unknown!",#PB_MessageRequester_Ok)
      ;
  EndSelect
EndProcedure


; IDE Options = PureBasic v3.94 (Windows - x86)
; Folding = g-


Posted: Thu Mar 09, 2006 11:19 pm
by chen
blueznl:

For newbes (like me :? ) could you update "survival guide" for PB4....

Some times when working with Automated Designers is dificult to implement
changes.... I need to stick the way of programming...etc, etc

Right now there is no a Designer ready for PB4..... and I prefer some guide from an expert.

thanks :wink:

Posted: Thu Mar 09, 2006 11:36 pm
by Paul
PureVision is available for both PureBasic 3.94 and PureBasic 4.0

Because PureBasic is still in beta stage, PureVision for PB4.0 is also listed as beta but many have been using it.

Posted: Thu Mar 09, 2006 11:51 pm
by chen
Paul...

Do you know if the code generated by PureVision runs in Win, Mac and Linux?

Cause I Believe, in some place I read it creates only windows code ...

thanks.

Posted: Thu Mar 09, 2006 11:56 pm
by blueznl

Code: Select all

; purebasic survival guide - pb4.00 b5
; mainloop_1.pb - 09.03.2006 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/purebasic.htm
;
; - basic framework
; - menus
; - event loop
; - gadgets
; - multi window handling
; - gadget and window resizing
;

Declare init()
Declare main()
init()
main()

Procedure init()
  ;
  ; *** all global declarations, enumeration stuff etc. ***
  ;
  ; enumeration is your best friend... i use it here to identify...
  ; - all functions of the program (actions taken)
  ; - all windows
  ; - all menus
  ; - all gadgets
  ;
  Enumeration
    ;
    ; functions - either real menu entries or logical functions
    ;
    #f_exit
    #f_show_child
    #f_close_child
    #f_toggle_child
    ;
    ; windows
    ;
    #w_main_nr
    #w_child_nr
    ;
    ; menus
    ;
    #m_main_nr
    ;
    ; gadgets main
    ;
    #g_main_exit
    #g_main_sample_listview
    #g_main_toggle_child
    ;
    ; gadgets child
    ;
    #g_child_close
    ;
  EndEnumeration
  ;
  ; add other global stuff
  ;
EndProcedure

Procedure reflect_settings()
  Global show_child.l
  ;
  ; *** show current settings in gadgets ***
  ;
  SetMenuItemState(#m_main_nr,#f_toggle_child,show_child)
  ;
EndProcedure

Procedure draw()
  Protected w.l, h.l
  Global w_main_h.l, w_child_h.l, show_child.l
  ;
  ; *** all draw, redraw, and resize routines ***
  ;
  ; this is the main drawing procedure, all setting up of windows, creation of gadgets
  ; and so on take place in here, this is also the place where you could store resizing
  ; code, this procedure does not update the status of gadgets or menus, for that
  ; reflect_settings() has to be called seperately
  ;
  ;
  ; *** main window ***
  ;
  If IsWindow(#w_main_nr)                        ; redraw or resize
    ;
    w = WindowWidth(#w_main_nr)
    h = WindowHeight(#w_main_nr)
    h = h-MenuHeight()-32
    ResizeGadget(#g_main_sample_listview,2,2,w-4,h-4)
    ResizeGadget(#g_main_toggle_child,2,h+4,w-4,24)
    ;
  Else                                           ; create the window
    ;
    w = 400
    h = 400
    w_main_h = OpenWindow(#w_main_nr,10,10,400,400,#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered,"Primary")
    ;
    CreateMenu(#m_main_nr,w_main_h)
    MenuTitle("&File")
    MenuItem(#f_show_child,"&Show child")
    MenuItem(#f_close_child,"&Close child")
    MenuItem(#f_toggle_child,"&Toggle child")
    MenuBar()
    MenuItem(#f_exit,"E&xit")
    ;
    h = h-MenuHeight()-32
    CreateGadgetList(w_main_h)
    ListViewGadget(#g_main_sample_listview,2,2,w-4,h-4)
    ButtonGadget(#g_main_toggle_child,2,h+4,w-4,24,"Toggle child")
    ;
  EndIf
  ;
  ; *** child window ***
  ;
  ; showing all other windows would depend on the value of the associated flags / variables
  ;
  If show_child = #True                          ; we want a window
    If IsWindow(#w_child_nr)                     ; window already exists, redraw or resize
      ;
    Else                                         ; create the window
      ;
      w_child_h = OpenWindow(#w_child_nr,10,10,110,110,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"Childwindow",w_main_h)
      CreateGadgetList(w_child_h)
      ButtonGadget(#g_child_close,2,2,108,108,"Close")
      ;
    EndIf
  Else                                           ; we donn't want a window
    If IsWindow(#w_child_nr)                     ; exists so close the window
      CloseWindow(#w_child_nr)
    Else                                         ; doesn't exist so don't bother
    EndIf
  EndIf
  ;
  ; repeat the above for any other window / gadget
  ;
EndProcedure

Procedure main_loop()
  Global event.l, event_gadget.l, event_window.l, event_menu.l, show_child.l
  ;
  draw()
  ;
  Repeat
    action = -1
    ;
    event = WaitWindowEvent()
    event_type = EventType()
    event_menu = EventMenu()
    event_window = EventWindow()
    event_gadget = EventGadget()
    ;
    ; i've set this up as following:
    ;
    ; 1. grab all events
    ; 2. process them per window
    ;    - first menu events
    ;    - then window events
    ;    - then gadgets
    ; 3. events either cause immediate actions, or they set the variable 'action'
    ;    (this allows me to have different events / gadgets / menu's to do the same thing)
    ; 4. if the action variable is non-zero it may cause certain actions as well
    ;
    Select event_window
    Case #w_main_nr
      ;
      ; process all events caused by the main window
      ;
      Select event
      Case #PB_Event_Menu
        action = event_menu
      Case #PB_Event_CloseWindow
        action = #f_exit
      Case #PB_Event_SizeWindow
        draw()
      Case #PB_Event_Gadget
        ;
        ; process all events caused by gadgets in the main window
        ;
        Select event_gadget
        Case #g_main_toggle_child
          action = #f_toggle_child
        Case #g_main_exit
          action = #f_exit
        Default
        EndSelect
        ;
      Default
      EndSelect
      ;
    Case #w_child_nr
      ;
      ; process all events caused by the child window
      ;
      Select event
      Case #PB_Event_Menu
        action = event_menu
      Case #PB_Event_CloseWindow
        action = #f_close_child
      Case #PB_Event_Gadget
        ;
        ; process all events caused by gadgets in the child window
        ;
        Select event_gadget
        Case #g_child_close
          action = #f_close_child
        Default
        EndSelect
        ;
      Default
      EndSelect
      ;
    EndSelect
    ;
    ;
    ; *** action section ***
    ;
    ; events either immediately take action (in the block above) or they
    ; set the action variable causing an action below
    ;
    Select action
    Case #f_show_child
      show_child = #True
      draw()
      reflect_settings()
    Case #f_close_child
      show_child = #False
      draw()
      reflect_settings()
    Case #f_toggle_child
      If show_child = #True
        show_child = #False
      Else
        show_child = #True
      EndIf
      draw()
      reflect_settings()
    EndSelect
    ;
  Until action = #f_exit
  ;
EndProcedure

Procedure main()
  Protected command.s
  ;
  ; in complex programs that support gui as well as command line functions i tend to
  ; seperate these two in two different sections
  ;
  command = ProgramParameter()
  Select command
  Case ""
    main_loop()
    ;
  Case "debug"
    MessageRequester("Command","Debug...",#PB_MessageRequester_Ok)
    ;
  Default
    MessageRequester("Command","Unknown!",#PB_MessageRequester_Ok)
    ;
  EndSelect
EndProcedure

Posted: Thu Mar 09, 2006 11:59 pm
by chen
blueznl:

faster than a thunder :wink:

thanks

Posted: Fri Mar 10, 2006 12:48 am
by Paul
chen wrote: Cause I Believe, in some place I read it creates only windows code.
Where did you read that?

I have used PureVision to design apps that run on both Windows and Linux.
I don't have Mac or access to one so no way for me to test on that OS.

Posted: Fri Mar 10, 2006 1:03 am
by chen
Paul:

It seems to me that it was a Guy from PureVision...... I was looking for an
email I sent to PureVision 2 months or so, let me see if i can get a demo.......

Maybe it was something confusing... perhaps they said: the software runs only in windows,
but they never specified if the code works in any OS.

Any way, is better to get the software...

thanks

Posted: Fri Mar 10, 2006 1:57 am
by chen
Ok Paul...

I went to PureVision Site and You are the developer.... true? :wink:

then you must know....

I'll wait for the final PV release for PB4, for me is useless
the current version.

Posted: Fri Mar 10, 2006 2:09 am
by Fangbeast
Blueznl, great job. You've shown me a way to stop my event from processing too many things needlessly in a multi-window environment and gained me some speed.

Just a question though..You state that the below is how you order the events and this puzzles me. Are no t meny events window events? Why would not not process window events first and then menu events?

Or have I missed something (Or am wrong as usual)?

; - first menu events
; - then window events
; - then gadgets

Posted: Fri Mar 10, 2006 4:37 am
by va!n
here a working version for PB4 beta6...
Ups, havent seen the beta5 version before, seems i have sleeped ^^

Code: Select all

; purebasic survival guide - pb4 beta 6
; mainloop_1.pb - 30.12.2005 ejn (blueznl)  v3.94 version
; mainloop_1.pb - 10.12.2006 (va!n)  v4 beta6 version
; http://www.xs4all.nl/~bluez/datatalk/purebasic.htm
;
; - basic framework
; - menus
; - event loop
; - gadgets
; - multi window handling
; - gadget and window resizing
;

Declare init()
Declare main()
init()
main()

Procedure init()
  ;
  ; *** all global declarations, enumeration stuff etc. ***
  ;
  ; enumeration is your best friend... i use it here to identify...
  ; - all functions of the program (actions taken)
  ; - all windows
  ; - all menus
  ; - all gadgets
  ;
  Enumeration
    ;
    ; functions - either real menu entries or logical functions
    ;
    #f_exit
    #f_show_child
    #f_close_child
    #f_toggle_child
    ;
    ; windows
    ;
    #w_main_nr
    #w_child_nr
    ;
    ; menus
    ;
    #m_main_nr
    ;
    ; gadgets main
    ;
    #g_main_exit
    #g_main_sample_listview
    #g_main_toggle_child
    ;
    ; gadgets child
    ;
    #g_child_close
    ;
  EndEnumeration
  ;
  ; add other global stuff
  ;
EndProcedure

Procedure reflect_settings()
  Global show_child.l
  ;
  ; *** show current settings in gadgets ***
  ;
  SetMenuItemState(#m_main_nr,#f_toggle_child,show_child)
  ;
EndProcedure

Procedure draw()
  Protected w.l, h.l
  Global w_main_h.l, w_child_h.l, show_child.l
  ;
  ; *** all draw, redraw, and resize routines ***
  ;
  ; this is the main drawing procedure, all setting up of windows, creation of gadgets
  ; and so on take place in here, this is also the place where you could store resizing
  ; code, this procedure does not update the status of gadgets or menus, for that
  ; reflect_settings() has to be called seperately
  ;
  ;
  ; *** main window ***
  ;
  If IsWindow(#w_main_nr)                        ; redraw or resize
    ;
  ;  UseWindow(#w_main_nr)
    w = WindowWidth(#w_main_nr)
    h = WindowHeight(#w_main_nr)
    h = h-MenuHeight()-32
    ResizeGadget(#g_main_sample_listview,2,2,w-4,h-4)
    ResizeGadget(#g_main_toggle_child,2,h+4,w-4,24)
    ;
  Else                                           ; create the window
    ;
    w = 400
    h = 400
    w_main_h = OpenWindow(#w_main_nr,10,10,400,400,"Primary",#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
    ;
    CreateMenu(#m_main_nr,w_main_h)
    MenuTitle("&File")
    MenuItem(#f_show_child,"&Show child")
    MenuItem(#f_close_child,"&Close child")
    MenuItem(#f_toggle_child,"&Toggle child")
    MenuBar()
    MenuItem(#f_exit,"E&xit")
    ;
    h = h-MenuHeight()-32
    CreateGadgetList(w_main_h)
    ListViewGadget(#g_main_sample_listview,2,2,w-4,h-4)
    ButtonGadget(#g_main_toggle_child,2,h+4,w-4,24,"Toggle child")
    ;
  EndIf
  ;
  ; *** child window ***
  ;
  ; showing all other windows would depend on the value of the associated flags / variables
  ;
  If show_child = #True                          ; we want a window
    If IsWindow(#w_child_nr)                     ; window already exists, redraw or resize
      ;
    Else                                         ; create the window
      ;
      w_child_h = OpenWindow(#w_child_nr,10,10,110,110,"Childwindow",#PB_Window_SystemMenu|#PB_Window_ScreenCentered,w_main_h)
      CreateGadgetList(w_child_h)
      ButtonGadget(#g_child_close,2,2,108,108,"Close")
      ;
    EndIf
  Else                                           ; we donn't want a window
    If IsWindow(#w_child_nr)                     ; exists so close the window
      CloseWindow(#w_child_nr)
    Else                                         ; doesn't exist so don't bother
    EndIf
  EndIf
  ;
  ; repeat the above for any other window / gadget
  ;
EndProcedure

Procedure main_loop()
  Global event.l, event_gadget.l, event_window.l, event_menu.l, show_child.l
  ;
  draw()
  ;
  Repeat
    action = -1
    ;
    event = WaitWindowEvent()
    event_type = EventType()
    event_menu = EventMenu()
    event_window = EventWindow()
    event_gadget = EventGadget()
    ;
    ; i've set this up as following:
    ;
    ; 1. grab all events
    ; 2. process them per window
    ;    - first menu events
    ;    - then window events
    ;    - then gadgets
    ; 3. events either cause immediate actions, or they set the variable 'action'
    ;    (this allows me to have different events / gadgets / menu's to do the same thing)
    ; 4. if the action variable is non-zero it may cause certain actions as well
    ;
    Select event_window
    Case #w_main_nr
      ;
      ; process all events caused by the main window
      ;
      Select event
      Case #PB_Event_Menu
        action = event_menu
      Case #PB_Event_CloseWindow
        action = #f_exit
      Case #PB_Event_SizeWindow
        draw()
      Case #PB_Event_Gadget
        ;
        ; process all events caused by gadgets in the main window
        ;
        Select event_gadget
        Case #g_main_toggle_child
          action = #f_toggle_child
        Case #g_main_exit
          action = #f_exit
        Default
        EndSelect
        ;
      Default
      EndSelect
      ;
    Case #w_child_nr
      ;
      ; process all events caused by the child window
      ;
      Select event
      Case #PB_Event_Menu
        action = event_menu
      Case #PB_Event_CloseWindow
        action = #f_close_child
      Case #PB_Event_Gadget
        ;
        ; process all events caused by gadgets in the child window
        ;
        Select event_gadget
        Case #g_child_close
          action = #f_close_child
        Default
        EndSelect
        ;
      Default
      EndSelect
      ;
    EndSelect
    ;
    ;
    ; *** action section ***
    ;
    ; events either immediately take action (in the block above) or they
    ; set the action variable causing an action below
    ;
    Select action
    Case #f_show_child
      show_child = #True
      draw()
      reflect_settings()
    Case #f_close_child
      show_child = #False
      draw()
      reflect_settings()
    Case #f_toggle_child
      If show_child = #True
        show_child = #False
      Else
        show_child = #True
      EndIf
      draw()
      reflect_settings()
    EndSelect
    ;
  Until action = #f_exit
  ;
EndProcedure

Procedure main()
  Protected command.s
  ;
  ; in complex programs that support gui as well as command line functions i tend to
  ; seperate these two in two different sections
  ;
  command = ProgramParameter()
  Select command
  Case ""
    main_loop()
    ;
  Case "debug"
    MessageRequester("Command","Debug...",#PB_MessageRequester_Ok)
    ;
  Default
    MessageRequester("Command","Unknown!",#PB_MessageRequester_Ok)
    ;
  EndSelect
EndProcedure


; IDE Options = PureBasic v3.94 (Windows - x86)
; Folding = g-

Posted: Fri Mar 10, 2006 11:49 pm
by blueznl
Fangbeast wrote:Blueznl, great job. You've shown me a way to stop my event from processing too many things needlessly in a multi-window environment and gained me some speed.

Just a question though..You state that the below is how you order the events and this puzzles me. Are no t meny events window events? Why would not not process window events first and then menu events?

Or have I missed something (Or am wrong as usual)?

; - first menu events
; - then window events
; - then gadgets
had to check it myself :-) but it's actually simple: i use a variable 'action' that is used to trigger certain actions (makes sense :-)) and i found that this sequence made my code easier to read FOR ME :-) there is no real other reason to do it this way