I started contemplating finding yet another alternative language before deciding maybe I don't need objects at all, maybe I can survive without them, maybe PureBasic, the compiler of small, fast executables was calling me home.
One of the things I've liked about OOP is being able to design a window, complete with it's own event handlers, and then being able to open any number of instances of it at run time. So this was the first thing I've tried to recreate in PureBasic and this is my first attempt - it's straight off the press so it might (probably) have some imperfections.
I have posted it here for any/all of the following reasons:
1) in the hope it's useful to someone else
or
2) someone else is going to show me a better way of doing it
or
3) someone's going to point out my bugs
The main window definition and event handlers 'pb_MainWindow.pb':
Code: Select all
;a structure and linked list for controlling instances of this window
;the structure has an element for each gadget on the window
;***EDIT***
;Structure MainWindow
; WindowID.l
; txtHello.l
;we could even add other properties here if we wanted
;EndStructure
;Global NewList mw.MainWindow()
;***END OF EDIT***
;the event handlers for this window
Procedure MainWindowEvents(WinID.l,Event.l,item.l,EventType.l)
ResetList(mw())
While NextElement(mw())
If mw()\WindowID = WinID
Select Event
Case -1
DeleteElement(mw())
Case #PB_Event_Gadget
Select item
Case mw()\txtHello
If EventType = #PB_EventType_Change
SetGadgetText(mw()\txtHello,"Why did you do that?")
EndIf
EndSelect
Case #PB_Event_Menu
EndSelect
ProcedureReturn
EndIf
Wend
EndProcedure
;the window definition
Procedure.l MainWindow()
lWindowID = OpenWindow(#PB_Any, 10, 10, 500, 500, "PureBasic - Window Instances Demonstration", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget)
If CreateGadgetList(WindowID(lWindowID))
lHello.l = StringGadget(#PB_Any, 10, 16, 180, 24, "Multiple Instances")
EndIf
WLoop.l = @MainWindowEvents() ;drop off the pointer to this forms event loop, this will get picked up when the procedure returns
;add an element to the list for our new window
AddElement(mw())
mw()\WindowID = lWindowID
mw()\txtHello = lHello
ProcedureReturn lWindowID
EndProcedure
Code: Select all
;a structure and linked list for controlling instances of this window
;the structure has an element for each gadget on the window
;***EDIT***
;Structure ChildWindow
; WindowID.l
; btnHello.l
;EndStructure
;Global NewList cw.ChildWindow()
;***END OF EDIT***
;a procedure just to demonstrate communicating between windows
Procedure SetTextToWinID(pWinID.l,cWinID.l)
;first one direction
ResetList(cw())
While NextElement(cw())
If cw()\WindowID = cWinID
SetGadgetText(cw()\btnHello,Str(pWinID))
Break
EndIf
Wend
;then the other
ResetList(cw())
While NextElement(cw())
If cw()\WindowID = pWinID
SetGadgetText(cw()\btnHello,Str(cWinID))
Break
EndIf
Wend
EndProcedure
;the event handlers for this window
Procedure ChildWindowEvents(WinID.l,Event.l,item.l,EventType.l)
ResetList(cw())
While NextElement(cw())
If cw()\WindowID = WinID
Select Event
Case -1 ;I've used this to denote the window being closed
DeleteElement(cw())
Case #PB_Event_Gadget
Select item
Case cw()\btnHello
lCloneID.l = ProjectWindow_Add(*WinChild,0,WinID)
SetTextToWinID(WinID,lCloneID)
EndSelect
Case #PB_Event_Menu
EndSelect
ProcedureReturn
EndIf
Wend
EndProcedure
Procedure.l ChildWindow()
lWindowID = OpenWindow(#PB_Any, 100, 200, 300, 100, "Click me to clone me", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget)
If CreateGadgetList(WindowID(lWindowID))
lHello.l = ButtonGadget(#PB_Any, 10, 16, 180, 24, "Click Me")
EndIf
WLoop.l = @ChildWindowEvents() ;drop off the pointer to this forms event loop, this will get picked up when the procedure returns
;add this instance to the linked list
AddElement(cw())
cw()\WindowID = lWindowID
cw()\btnHello = lHello
ProcedureReturn lWindowID
EndProcedure
Code: Select all
Global AppMain.l ;the id of the main application window
Global WLoop.l ;a drop off point for the memory address of the event loop for the window we're opening
;we need a pointer for each window creation procedure (the procedure, not each individual instance of a window)
Global *WinMain
Global *WinChild
;a structure and linked list for monitoring currently open windows
Structure ProjectWindow
WindowID.l
WindowType.l
EventLoop.l
CalledFromID.l ;so a window can determine which other window called it
EndStructure
Global NewList pw.ProjectWindow()
;***EDIT***
;a structure and linked list for controlling instances of the main window
;the structure has an element for each gadget on the window
Structure MainWindow
WindowID.l
txtHello.l
;we could even add other properties here if we wanted
EndStructure
Global NewList mw.MainWindow()
;a structure and linked list for controlling instances of the child window
;the structure has an element for each gadget on the window
Structure ChildWindow
WindowID.l
btnHello.l
EndStructure
Global NewList cw.ChildWindow()
;***END OF EDIT***
;get the id of the calling window
Procedure.l ProjectWindow_CalledFrom(WinID.l)
ResetList(pw())
While NextElement(pw())
If pw()\WindowID = WinID
ProcedureReturn pw()\CalledFromID
EndIf
Wend
ProcedureReturn -1 ;no parent or parent has been closed
EndProcedure
;to create a new instance of a particular window
Procedure.l ProjectWindow_Add(WinType.l,MainAppWindow.l,CallingWin.l)
lresult.l = CallFunctionFast(WinType)
If MainAppWindow = 1:AppMain = lresult:EndIf
;add the new window to the control list
AddElement(pw())
pw()\WindowID = lresult
pw()\WindowType = WinType
pw()\EventLoop = WLoop
pw()\CalledFromID
ProcedureReturn lresult
EndProcedure
;to close a particular instance of a window
Procedure ProjectWindow_Remove(WinID.l)
ResetList(pw())
While NextElement(pw())
If pw()\WindowID = WinID
lType.l = pw()\WindowType
DeleteElement(pw())
CallFunctionFast(pw()\EventLoop,WinID,-1,0,0)
CloseWindow(WinID)
ProcedureReturn
EndIf
Wend
EndProcedure
;for passing an event to the relevant windows event handlers
Procedure ProjectEvent(WinID.l,Event.l,item.l,EventType.l)
ResetList(pw())
While NextElement(pw())
If pw()\WindowID = WinID
CallFunctionFast(pw()\EventLoop,WinID,Event,item,EventType)
ProcedureReturn
EndIf
Wend
EndProcedure
;include each window and set the pointer to the window definition procedure
XIncludeFile "pb_MainWindow.pb"
*WinMain = @MainWindow()
XIncludeFile "pb_ChildWindow.pb"
*WinChild = @ChildWindow()
;and we're away
;open the main app window
lMain.l = ProjectWindow_Add(*WinMain,1,-1)
;an instance of the child window called by the main window
ProjectWindow_Add(*WinChild,0,lMain)
Repeat ;the main event loop that branches off to form instances when applicable
EventID = WaitWindowEvent()
EventWindowID = EventWindow()
If EventID = #PB_Event_CloseWindow And EventWindowID <> AppMain:ProjectWindow_Remove(EventWindowID):EndIf
EventKindID.l = EventType()
If EventID = #PB_Event_Gadget
EventItemID.l = EventGadget()
ElseIf EventID = #PB_Event_Menu
EventItemID.l = EventMenu()
EndIf
ProjectEvent(EventWindowID,EventID,EventItemID,EventKindID)
Until EventID = #PB_Event_CloseWindow And EventWindowID = AppMain
End