Example of OOP GUI App needed.
BlitzMax Forums/BlitzMax Beginners Area/Example of OOP GUI App needed.| 
 | ||
| I've had to start from scratch with my app and want to go about it using OOP. Can anyone post some code that shows how to create a window with a canvas but using OOP and being able to check for events? It may sound like a lot but I kind of don't know where to start. In the mean time I'll start coding. Thanks :) | 
| 
 | ||
| 
Strict
Type TAmon
	Field window:TGadget
	Field canvas:TGadget
	Field button:TGadget
	
	Field clsR:Byte
	Field clsG:Byte
	Field clsB:Byte
	
	Method ev()
		If EventSource()=canvas
			If EventID()=EVENT_GADGETPAINT
				update
			EndIf
			If EventID()=EVENT_MOUSEMOVE
				clsR=EventX()
				clsG=EventY()
				update
			EndIf
		EndIf
		If EventSource()=button
			clsR=Rnd(255)
			clsG=Rnd(255)
			clsB=Rnd(255)
			update
		EndIf
	End Method
	
	Method update()
		SetGraphics CanvasGraphics(canvas)
			SetClsColor clsR,clsG,clsB
			Cls
		Flip
	End Method
	
End Type
'
' a seperate create function to make it a bit more like the other blitz commands
'
Function CreateAmon:TAmon(x:Int,y:Int,w:Int,h:Int)
	Local a:TAmon=New TAmon
	a.window=CreateWindow("kamikaze",x,y,w,h)
	a.canvas=CreateCanvas(0,0,w-80,h,a.window)
	a.button=CreateButton("O_o",w-80,0,70,32,a.window)
	SetGadgetLayout a.canvas,1,0,1,0
	Return a
End Function
Local a:TAmon=CreateAmon(32,32,512,256)
OnEnd quit
Repeat
	WaitEvent()
	a.ev
	If EventID()=EVENT_WINDOWCLOSE End
Forever
Function quit()
	GCCollect()
	End
End Function
Note that it still has manual event-checking (a.ev), haven't 100% got yet how to do the eventhook stuff, and how to emit events. It's probably not that hard, but the manual is kinda minimalistic on that.. | 
| 
 | ||
| This is perfect. Thanks dude. :) | 
| 
 | ||
| Heres a quick demo using an eventhook... | 
| 
 | ||
| Fab! Finally an eventhook example that isn't written for cyborgs! Examples should be minimalistic, lotsa examples are often large pieces o' non-modular code. Papa^2 ! Now, can you add the same style o' tut to this about own events? imagine this chunk being added to your mainloop, right under Waitevent() If EventID()= <New custom ID number here> If EventSource()=<ID of source here> Notify "papa!" EndIf EndIf Now for example let a mousedown on that canvase create a new eventID. Meaning I can work with such an object *everywhere* (since EventID(), EventSource() and all the other Event-things are globals) So in short: mousedown on canvas should trigger the notify 'papa!' | 
| 
 | ||
| . I try to keep the main loop empty, thats what events are for ;) | 
| 
 | ||
| no, globally I meant, not as part of the object, it really has to emit an event. Imagine I'm making a GUI-object like a spinner orso, I simply create it like any other gadget, and anywhere in any part of the whole source, in any object, I should be able to read it out by checking the globals EventID() etc. | 
| 
 | ||
| Mind you the custom event could also be caught by the eventhook :) | 
| 
 | ||
| Nicenice! For completeness and non-globalness I'd say: Const CustomEvent = 1 (..) Field NewEvent:TEvent = New TEvent (..) and NewEvent.ID = CustomEvent in Method New() Saves globals.. the less globals the better, I always figure..! | 
| 
 | ||
| Ok, I think I get the hang of it, just before the emitevent in that method I put this: NewEvent.source=Self Et Voila, in my mainloop I can now check on EventSource being App ... and add this NewEvent.x=Event.x before the emitevent means I can readout EventX() in my mainloop .. Ok, eventhook rocks, Papa next time you should write the bmax manual ^_^ | 
| 
 | ||
| You got it CS, its easier than it seems isn't it :) | 
| 
 | ||
| Well things being easy depends on who teaches it. As good as the manual for B+ was, as weak is the manual for Bmax. While I can understand that BRL doesn't always have the time to polish manuals, it's still highly required. B+'s manual was really excellent for that matter.. One could ask on the forum, but a *lot* of coders either have their backgrounds in game-programming, which seems to lead to a completely different code-style (probably NOT event-based), or aren't thinking modular enough to come up with the perfect example-code. | 
| 
 | ||
| I made some GUI-object, need to add some free-up method: Method Free() End Method I figure I can kill the created gadgets easily with: Method Free() canvas=null button=null gccollect() End Method However, how do I get rid of the eventhook for this object? The manual is as zero'ish as it is ever: Function RemoveHook( id,func:Object( id,data:Object,context:Object ) ) I figure 'id' could be 'self' ? And what is that func stuff/how to use it? | 
| 
 | ||
| I've Updated the example with a Delete method, which is called automatically by BlitzMax when the object is released. (same as the new method is called when a new object is created) | 
| 
 | ||
| ah, nice. When/how is an object released actually? When I do: App=null ? Or only after App=null and some garbagecollecting? Or what else? :P | 
| 
 | ||
| I think the GC calls the Delete method just before it releases the object from memory (when there is no more references to that object). | 
| 
 | ||
| I just tested it, I put a notify "bla" in the Delete method, but nothing is ever notified when I 'End' or 'App=null'.. My OnEnd function also runs a GCCollect, so plenty o' opportunities to show my those notifications.. sofar: zippo~ | 
| 
 | ||
| Yeah I've just been doing that too :( Change Delete to Free and call app.free and it works. Is it a bug BRL? *EDIT* It works fine if you comment out the hook stuff. Seems that the GC never gets used because there is still a reference to the object... in the hook! so its not really a bug, should be mentioned in the docs tho ;) | 
| 
 | ||
| well, bug or not, I figured a manual free-up would work. The primary question was about that RemoveHook anyway. I figure my first-ever-hooked-gadget is kinda ready then, a multimulti-functional spinnergadget. ^_^ One of these days it'll appear in the code-archives. Sofar it works like other gadgets (except the gadget-modifying like Setgadgetshape etc. but I rarely/never use that anyway). An interesting thread this became, it by now contains a full howto for eventhooks, far better understandable than any other attempts I've seen sofar! | 
| 
 | ||
| papa to the rescue! Move the green windows around and observe! ._. 
SuperStrict
Type Tbla
	
	Field canvas:TGadget
	Field c:Int
	Function eventhook:Object(id:Int,data:Object,context:Object)
		If Tbla(context) Tbla(context).ev TEvent(data);Return data	
	EndFunction
	
	Method New()
		AddHook EmitEventHook,eventhook,Self
	End Method
	
	Method Free()
		RemoveHook EmitEventHook,eventhook
		GCCollect()
	End Method
	
	Method ev(event:TEvent)
		If Event.source=canvas
			If Event.id=EVENT_GADGETPAINT update
		EndIf
	End Method
	
	Method update()
		SetGraphics CanvasGraphics(canvas)
			SetClsColor c,255-c,c;Cls
		Flip
	End Method
			
End Type
Function CreateBla:Tbla(parent:TGadget)
	Local a:TBla=New TBla
	a.canvas=CreateCanvas(0,0,128,128,parent)
	a.c=Rnd(255)
	Return a
End Function
Local window:TGadget=CreateWindow("o_O",0,0,640,480)
Local w1:TGadget=CreateWindow("1",50,50,128,128,window,1|WINDOW_CHILD)
Local w2:TGadget=CreateWindow("2",90,90,128,128,window,1|WINDOW_CHILD)
Local bla1:TBla=CreateBla(w1)
Local bla2:TBla=CreateBla(w2)
Repeat
	WaitEvent()
	If EventID()=EVENT_WINDOWCLOSE End
Forever
The WINDOW_CHILD is basically to blame here, without it there's no harm. However I want to make sure it's something I'm doing wrong/could fix, before it goes to the bug-submit orso. | 
| 
 | ||
| Its a known issue... http://www.blitzmax.com/Community/posts.php?topic=55777 | 
| 
 | ||
| hi with the following code: 
Strict
Type TTestApp
	Field Window:TGadget = CreateWindow("",0,0,640,480)
	Field Button:TGadget = CreateButton("BUTTON",0,0,100,20,Window)
	Field Canvas:TGadget = CreateCanvas(0,20,ClientWidth(window),ClientHeight(window)-20,window,PANEL_BORDER)
	
	Method New()
		AddHook EmitEventHook,eventhook,Self
		Button.SetLayout(1,0,1,0)
		Canvas.SetLayout(1,1,1,1)
	EndMethod	
	
	Function eventhook:Object(id,data:Object,context:Object)
		If TTestApp(context) Then TTestApp(context).OnEvent TEvent(data)
		Return data	
	EndFunction
	
	Method OnEvent(event:TEvent)
		Select event.id
		
			Case EVENT_WINDOWCLOSE
				Select Event.Source
					Case window
						End
				End Select
				
			Case EVENT_GADGETACTION
				Select Event.Source
					Case Button
						Notify "You pressed the button"
				EndSelect
			
			Case EVENT_GADGETPAINT
				Select Event.Source
					Case Canvas
						SetGraphics(CanvasGraphics(canvas))
						SetViewport(0,0,ClientWidth(canvas),ClientHeight(canvas))
						Cls
						DrawText "TEST CANVAS",10,10
						Flip 0
				EndSelect
				
		EndSelect
	EndMethod
	
EndType
Global App:TTestApp = New TTestApp
While True
	WaitEvent()
Wend
should i not be able to do Global App:TTestApp = New TTestApp Global App2:TTestApp = New TTestApp ...although if i do it throws and error with the line? | 
| 
 | ||
| Works for me. What error do you get? | 
| 
 | ||
| Global App:TTestApp = New TTestApp by itself is ok, but if i do Global App:TTestApp = New TTestApp Global App2:TestApp = New TTestApp it stops at the event.id with an error about accessing property of a null object? | 
| 
 | ||
| You said... global app2:TestApp = New TTestApp rather than global app2:TTestApp = New TTestApp Correcting that on Bmax 1.16 and it works as expected. | 
| 
 | ||
| sorry just my spelling mistake, it is TTestApp -  its just my keyboard at work and the keys stick...lol will try again at home |