Separate event loop for each form

Share your advanced knowledge/code with the community.
the.weavster
Posts: 220
Joined: Sat Mar 01, 2014 3:02 pm

Separate event loop for each form

Post by the.weavster »

It's been a long while since I've used PureBasic but SpiderBasic has rekindled my interest. I want a way of having a separate event loop for each form in my applications (I think having an overarching event loop could get very unwieldy in a large application) and also to account for the fact SpiderBasic doesn't seem to support the WindowEvent() command, furthermore I wanted the code to work for SpiderBasic and PureBasic without changes.

Below is a 'Hello World' example posted in the hope the program structure I've come up with is useful to someone (and also in the hope if there's a flaw in my thinking someone will point it out :) ):


Main.pb which is the program's entry point and contains an outer event loop that simply passes off any events to the event loop in the appropriate form. It also opens the program's main form...

Code: Select all

XIncludeFile "EventBindings.pb" ; bindings as a substitute for WindowEvent()

; import all the form definitions before the event loops or else the IDs wont work
XIncludeFile "frmMain_UI.pbf"   ; frmMain (apps main form as output by form designer)

; import event loop, event handlers and procedures for each form
XIncludeFile "frmMain_FN.pb"    ; frmMain functions and loop


; procedure for outer event loop
; (event is just passed on to event handlers of the relevant window)
Procedure ProcessEvents(nEvent)
  Select EventWindow()
    Case frmMain : frmMain_Events(nEvent)
    ; do the same for any other forms
  EndSelect
EndProcedure

OpenfrmMain()  ; Open the main application window
frmMain_Init() ; To do any additional initialisation without editing form designer output
  
; loop required for PureBasic
CompilerIf #PB_Compiler_OS <> #PB_OS_Web
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow And EventWindow() = frmMain
CompilerEndIf
EventBindings.pb is a file that binds all (??) events associated with WindowEvent() to callbacks that in turn call the outer event loop in Main.pb as described above...

Code: Select all

#PB_OS_Web = 5 ; because PureBasic compiler doesn't know this constant yet
Declare ProcessEvents(nEvent) ; the outer event loop that will be defined in Main.pb

; this may not be an exhaustive list of
; the constants returned by WindowEvent()
Procedure LeftClickEvent()
  ProcessEvents(#PB_Event_LeftClick)
EndProcedure

Procedure LeftDoubleClickEvent()
  ProcessEvents(#PB_Event_LeftDoubleClick)
EndProcedure

Procedure RightClickEvent()
  ProcessEvents(#PB_Event_RightClick)
EndProcedure

Procedure GadgetEvents()
  ProcessEvents(#PB_Event_Gadget)
EndProcedure

Procedure MenuEvents()
  ProcessEvents(#PB_Event_Menu)
EndProcedure

Procedure TimerEvent()
  ProcessEvents(#PB_Event_Timer)
EndProcedure

Procedure WindowActivateEvent()
  ProcessEvents(#PB_Event_ActivateWindow)
EndProcedure

Procedure WindowCloseEvent()
  ProcessEvents(#PB_Event_CloseWindow)
EndProcedure

Procedure WindowDeactivateEvent()
  ProcessEvents(#PB_Event_DeactivateWindow)
EndProcedure

Procedure WindowMaximizeEvent()
  ProcessEvents(#PB_Event_MaximizeWindow)
EndProcedure

Procedure WindowMinimizeEvent()
  ProcessEvents(#PB_Event_MinimizeWindow)
EndProcedure

Procedure WindowMoveEvent()
  ProcessEvents(#PB_Event_MoveWindow)
EndProcedure

Procedure WindowRestoreEvent()
  ProcessEvents(#PB_Event_RestoreWindow)
EndProcedure

Procedure WindowSizeEvent()
  ProcessEvents(#PB_Event_SizeWindow)
EndProcedure

Procedure FirstCustomValue()
  ProcessEvents(#PB_Event_FirstCustomValue)
EndProcedure

BindEvent(#PB_Event_LeftClick,@LeftClickEvent())
BindEvent(#PB_Event_LeftDoubleClick,@LeftDoubleClickEvent())
BindEvent(#PB_Event_RightClick,@RightClickEvent())
BindEvent(#PB_Event_Gadget,@GadgetEvents())
BindEvent(#PB_Event_Menu,@MenuEvents())
BindEvent(#PB_Event_Timer,@TimerEvent())
BindEvent(#PB_Event_ActivateWindow,@WindowActivateEvent())
BindEvent(#PB_Event_CloseWindow,@WindowCloseEvent())
BindEvent(#PB_Event_DeactivateWindow,@WindowDeactivateEvent())
BindEvent(#PB_Event_MaximizeWindow,@WindowMaximizeEvent())
BindEvent(#PB_Event_MinimizeWindow,@WindowMinimizeEvent())
BindEvent(#PB_Event_MoveWindow,@WindowMoveEvent())
BindEvent(#PB_Event_RestoreWindow,@WindowRestoreEvent())
BindEvent(#PB_Event_SizeWindow,@WindowSizeEvent())
BindEvent(#PB_Event_FirstCustomValue,@FirstCustomValue())

CompilerIf #PB_Compiler_OS = #PB_OS_Web
  
Procedure ResourceLoading()
  ProcessEvents(#PB_Event_Loading)
EndProcedure

Procedure ResourceLoadingError()
  ProcessEvents(#PB_Event_LoadingError)
EndProcedure

BindEvent(#PB_Event_Loading,@ResourceLoading())
BindEvent(#PB_Event_LoadingError,@ResourceLoadingError())
  
CompilerElse
  
Procedure GadgetDropEvent()
  ProcessEvents(#PB_Event_GadgetDrop)
EndProcedure

Procedure RepaintEvent()
  ProcessEvents(#PB_Event_Repaint)
EndProcedure

Procedure SysTrayEvent()
  ProcessEvents(#PB_Event_SysTray)
EndProcedure

Procedure WindowDropEvent()
  ProcessEvents(#PB_Event_WindowDrop)
EndProcedure

BindEvent(#PB_Event_GadgetDrop,@GadgetDropEvent())
BindEvent(#PB_Event_Repaint,@RepaintEvent())
BindEvent(#PB_Event_SysTray,@SysTrayEvent())
BindEvent(#PB_Event_WindowDrop,@WindowDropEvent())

CompilerEndIf
Then for each form there are two files, the one output by PureBasic's form designer, which is left untouched...

Code: Select all

;
;
; This code is automatically generated by the FormDesigner.
; Manual modification is possible to adjust existing commands, but anything else will be dropped when the code is compiled.
; Event procedures needs to be put in another source file.
;

Global frmMain

Global frmMain_btnHello, frmMain_txtHello

Declare ResizeGadgetsfrmMain()


Procedure OpenfrmMain(x = 3, y = 3, width = 510, height = 180)
  frmMain = OpenWindow(#PB_Any, x, y, width, height, "Hello")
  frmMain_btnHello = ButtonGadget(#PB_Any, 10, 10, 100, 25, "Say Hello")
  frmMain_txtHello = StringGadget(#PB_Any, 120, 10, 370, 25, "")
EndProcedure

Procedure ResizeGadgetsfrmMain()
  Protected FormWindowWidth, FormWindowHeight
  FormWindowWidth = WindowWidth(frmMain)
  FormWindowHeight = WindowHeight(frmMain)
  ResizeGadget(frmMain_txtHello, 120, 10, FormWindowWidth - 140, 25)
EndProcedure
and another that contains the form's methods and event loop...

Code: Select all

Procedure frmMain_Resize()
  ; there currently seems to be a layout bug 
  ; with SpiderBasic so give the positions a tweak
  CompilerIf #PB_Compiler_OS = #PB_OS_Web
    ResizeGadget(frmMain_txtHello,130,13,360,-1)
  CompilerEndIf
EndProcedure

Procedure frmMain_Init()
  frmMain_Resize()
EndProcedure

Procedure frmMain_Window_Event(nEvent)
  Select nEvent
      Case #PB_Event_ActivateWindow : Debug "Activate"
      Case #PB_Event_MaximizeWindow : Debug "Maximize"
      Case #PB_Event_MinimizeWindow : Debug "Minimize"
      Case #PB_Event_MoveWindow     : Debug "Move"
      Case #PB_Event_SizeWindow     : frmMain_Resize()
  EndSelect
EndProcedure

Procedure frmMain_btnHello_Event(nType)
  SetGadgetText(frmMain_txtHello,"Hello World!")
EndProcedure

Procedure frmMain_txtHello_Event(nType)
  Select nType
    Case #PB_EventType_Change    : Debug "Change"
    Case #PB_EventType_Focus     : Debug "Focus"
    Case #PB_EventType_LostFocus : Debug "Lost Focus"
    Default                      : Debug nType ; we get more events here with PB than SB
  EndSelect  
EndProcedure

Procedure frmMain_Events(nEvent)
  nType = EventType()
  Select nEvent
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
          
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case frmMain_btnHello : frmMain_btnHello_Event(nType)  
        Case frmmain_txtHello : frmMain_txtHello_Event(nType)
      EndSelect
      
    Default
      frmMain_Window_Event(nEvent)
  EndSelect
  ProcedureReturn #True
EndProcedure
Weave.