Events, Hooks etc

BlitzMax Forums/BlitzMax Beginners Area/Events, Hooks etc

tonyg(Posted 2006) [#1]
I am not using MaxGUI but would like to understand Events and Hooks but find the documentation VERY poor.
As a test I would like to create a timer which, when ticked, issues a MY_EVENT. However, I have no idea how to use CreateEvent. The parms (id,source:Object=Null,data=0,mods=0,x=0,y=0,extra:Object=Null ) are not exactly self-explanatory.
Leaving the defaults and specifying CreateEvent(MY_EVENT) fails with 'ID MY_EVENT not found'.
I can get past this by creating a function called MY_EVENT but I'm now off into the unknown.
Anybody able to help?

<edit> Blimey, got the first bit to work...
SuperStrict
Graphics 800,600
Local MY_EVENT:TEvent=CreateEvent(69)
Local myTimer:TTImer = CreateTimer(3,MY_EVENT)
While EventID() <> EVENT_KEYDOWN
	WaitEvent
	If EventID() = 69
		Print "Timer has ticked " + TimerTicks(myTimer) + " times"
	EndIf
EndWhile

but from trial+error.


assari(Posted 2006) [#2]
Have you checked out the The MaxGUI Beginner Tutorial Series?. Events are explained starting from Tutorial 2 and eventhooks in Tutorial 15


tonyg(Posted 2006) [#3]
Hi Assari, I've read those and they help to some degree but still don't explain how to use these functions outside your tutorial (which is understandable).
e.g.

Function AddHook( id,func:Object( id,data:Object,context:Object ),context:Object=Null,priority=0 )


What is id, data:object, context:object etc)?
It's even possible what I'm hoping to do is not possible BUT, without knowing what *CAN* be done it's hard to know.
The idea is to CreateTimer specifying an event_id then, when that event occurs to hook into other code.
E.g. When EVENT_TIMER occurs for that TTimer to run a specific function automatically.
Even if that is NOT possible I still want to understand how to use events/hooks outside MaxGui whether I need them, can use them or end up hating them (I know which is favourite at the moment).
Thanks for your help so far and excellent tutorials.


CS_TBL(Posted 2006) [#4]
that function looks alien, and the manual is poor. yes!

Use this template, I use it always, and forget about the meaning of that function or the poor'ish manual :P

Type MyType

	Field NewEvent:TEvent=New TEvent ' if you need to emit events
	
	Function eventhook:Object(id:Int,data:Object,context:Object)
		If MyType(context) MyType(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.id
		EndIf
		
		If Event.source
		EndIf

		If Event.x
			NewEvent.source=Self
			EmitEvent NewEvent
		EndIf

		If Event.y
		EndIf
		
		' etc.
		
								
	End Method
	
End type


(don't forget to change the MyType names in that eventhook-function!)


tonyg(Posted 2006) [#5]
Hmmm. so I've managed to emit event 69 each time my CreateTimer ticks.
How would I use that template (or any other method) to add a hook which checked for my event 69 and output "Hello World!" when 69 occurs?
<edit> So, I now have a hook using fliphook and a user-event...
Function MyHook:Object( id,data:Object,context:Object )
   Print "Hello World!"
End Function


Local MY_EVENT:TEvent=CreateEvent(69)
Local myTimer:TTImer = CreateTimer(3,MY_EVENT)
'Add our hook to the system
AddHook FlipHook,MyHook
Graphics 800,600
While EventID() <> EVENT_KEYDOWN
	WaitEvent
	If EventID() = 69
		Print "Timer has ticked " + TimerTicks(myTimer) + " times"
	EndIf
               flip
EndWhile

How would I link the2 together so "Hello World!" is displayed when the timer ticks? I tried with EmitEventHook but I'm then back into the realms of confusion.


CS_TBL(Posted 2006) [#6]
try this (in debugmode, watch the log).., it only uses the GUI because I'm used to it :P
SuperStrict
Type MyType
	Field timer:TTimer
	Field NewEvent:TEvent=New TEvent
	
	Function eventhook:Object(id:Int,data:Object,context:Object)
		If MyType(context) MyType(context).ev TEvent(data);Return data	
	EndFunction
	
	Method New()
		AddHook EmitEventHook,eventhook,Self
		timer=CreateTimer(3)
	End Method
	
	Method Free()
		RemoveHook EmitEventHook,eventhook
		GCCollect()
	End Method
	
	Method ev(event:TEvent)
		If Event.id=EVENT_TIMERTICK
			NewEvent.source=Self
			NewEvent.id=69
			DebugLog "hooked timertick!"
			EmitEvent NewEvent
			
		EndIf
		
	End Method
	
End Type

Local window:TGadget=CreateWindow("O_O",200,200,640,480)

Local mooh:MyType=New MyType

Repeat
	WaitEvent()
	If EventID()=EVENT_WINDOWCLOSE End
	If EventID()=69
		If EventSource()=mooh DebugLog "mooooh!"
	EndIf
Forever


btw: drag the window around to see the difference between 'hooks' vs 'no hooks'


tonyg(Posted 2006) [#7]
Thanks, think I've got it...
SuperStrict
Const TICK_EVENT:Int=69
Function MyHook:Object( id:Int,data:Object,context:Object )
	Local ev:TEvent=TEvent(data)
	
      Select ev.id
            Case TICK_EVENT
               Print "Hello World!"
            Default
               Print "Not interested!" 
      End Select

End Function


Local MY_EVENT:TEvent=CreateEvent(TICK_EVENT)
Local myTimer:TTImer = CreateTimer(3,MY_EVENT)
'Add our hook to the system
AddHook EmitEventHook,MyHook
Graphics 800,600
While EventID() <> EVENT_KEYDOWN
	WaitEvent
	Flip
EndWhile

<edit> How would I get an Event_ID without supplying a random number myself?


Dreamora(Posted 2006) [#8]
Strange ... why does this work with own defined Event constants but not if you would use EVENT_TIMERTICK and check if TEvent(data).source = timer ...
Haven't been able to find a usefull reason why it should not work with source check but event id check ...

But a good small example, but both are good examples (think especially the timer one might be interesting for "pseudo threaded" networking :-)

Note: the good thing is that these event stuff even works when no event commands are used at all. This is a really usefull thing.

Thank you :-)


On the question: This is not possible at the moment. You need to specify the event with a number. But for the sake of all the other events that can be fired by the OS, it would be great if we had a command that returned the next free event number because I don't think we all are gods and know all the possible event numbers over all 3 OSes ;-)


tonyg(Posted 2006) [#9]
Think there should be an event_id equivalent of AllocHookID
Possibly a better example...
SuperStrict
Const TICK_EVENT:Int=69
Function MyHook:Object( id:Int,data:Object,context:Object )
	Local ev:TEvent=TEvent(data)
	
      Select ev.id
            Case TICK_EVENT
               Print "Hello World!"
      End Select

End Function
Local MY_EVENT:TEvent=CreateEvent(TICK_EVENT)
Local myTimer:TTImer = CreateTimer(4,MY_EVENT)
'Add our hook to the system
AddHook EmitEventHook,MyHook
Graphics 800,600
Local time:Int=MilliSecs()+500
While EventID() <> EVENT_KEYDOWN
    If MilliSecs()>=time
       Print "1/2 second"
       time=MilliSecs()+500
    EndIf
	PollEvent
EndWhile

I was probably lucky as event_id 69 was on the tip of my tongue.
If you replace TICK_EVENT with EVENT_TIMERTICK it works the same way but I was hoping for a way to only call MY_HOOK automatically when TICK_EVENT occurred.


CS_TBL(Posted 2006) [#10]
All things non-event, dunno, scare me :P Since B+ I really ditched all polled stuff orso. I don't exactly see what you're coding atm, and whether there're full-event solutions, with no polling whatsoever..

back to the pollingmasters with the question :P


tonyg(Posted 2006) [#11]
I'm just trying to find out how to use these things rather than have an end in mind.
In this case I could use the standard EVENT_TIMERTICK
with the same hook but was just trying things out.
I still want to understand all the gubbings about 'context:object' and 'mods' etc but I REALLY want this documented both out of principle and to save what little hair I have left.


Dreamora(Posted 2006) [#12]
Mods etc are internal values that you can send with an event. For example the mouse sends with its x,y (position), other events send mods (modifier key values) or even extra (which is great if you want to have an object fired on event ... for example if we could do a collision event this would be extremely handy to specify the other colided object)


tonyg: Yes it works if I ask for the ID. The problem is that I have more than one timer in and that I need a specific one and if I check for TEvent(data).source = timer.
But for some reason tevent(data).source is null which makes totally no sense. It seems like starting an eventhook within a method or creating a type global timer, which emits the event just don't work ... have to find out which part it is (or if it is somehow related to private).
The timer is created, that part is already checked ...

stupid inconsistent behavior of BM is really making me angry and frustrates me


Taron(Posted 2008) [#13]
It's stunning that this is 2 years ago already! I suppose the screaming wasn't loud enough, haha!

Timers, as far as I can tell, are the nightmare of beginners for sure. The Event handling is only understandable up until the point when you introduce timers. The moment a timer is running, all bets are off, Eventsources become exterminated and replaced by timers, other queues overwritten and ignored and systems get bellyflopped until the timer has enough of a hickup to inject a little "escape" for closing the window, haha. Let me add again that I can only speak for beginners, since I'm one of them, but it somehow feels as though it ain't getting too much better after knowing more. I sure hope I'm wrong, though. I like to believe that very much!