While reviewing the code for WindowResizerClass (in an attempt to get more agreeable resizing behavior for ClarionTest) I came across a usage of RegisterEvent that I hadn't noticed before:
REGISTEREVENT (EVENT:DoResize, ADDRESS(SELF.TakeResize), ADDRESS(SELF))
The help says this about RegisterEvent:
REGISTER registers an event handler PROCEDURE called internally by the currently active ACCEPT loop of the specified window whenever the specified event occurs. This may be a User-defined event, or any other event. User-defined event numbers can be defined as any integer between 400h and 0FFFh.
Register is a synonym for RegisterEvent - I suggest using the latter as it's more descriptive. Basically this means that RegisterEvent installs a callback procedure for your accept loop, to be called whenever the specified event occurs. You can install event handlers for windows and for individual controls.
The bit I hadn't noticed was the ability to specify a class method as the callback by passing in the address of the method and the address of the class.
Using class methods as callbacks in Clarion is often problematic because internally the first parameter to any method is the class itself. This is why using Omitted(parameternumber) is unwise with class methods that have optional parameters - if the first parameter of a method is omittable, you have to specify Omitted(2) rather than Omitted(1). Just use Omitted(parametername) - it will save you a lot of trouble.
Similarly, you can't use class methods as WinAPI callbacks because of that hidden first parameter.
But RegisterEvent is part of the Clarion runtime, and it's smart enough to handle a method if that's what you throw at it.
Here's a small sample program to demonstrate:
Code Block |
---|
PROGRAM
EventQueue queue,type
EventTime long
end
EventHandler class
EventQ &EventQueue
Construct procedure
Destruct procedure
TakeEvent procedure,long
end
MAP
END
Window WINDOW('Caption'),AT(,,176,262),GRAY,FONT('Microsoft Sans Serif',8),TIMER(100)
LIST,AT(3,2,169,257),USE(?LIST1),FROM(EventHandler.EventQ), |
FORMAT('20L(2)|M@t4@')
END
CODE
open(window)
accept
case event()
of EVENT:OpenWindow
RegisterEvent(event:timer,address(EventHandler.TakeEvent),address(EventHandler))
end
end
UnRegisterEvent(event:timer,address(EventHandler.TakeEvent),address(EventHandler))
EventHandler.Construct procedure
code
self.EventQ &= new EventQueue
EventHandler.Destruct procedure
code
free(self.EventQ)
dispose(self.EventQ)
EventHandler.TakeEvent procedure
code
self.EventQ.EventTime = clock()
add(self.EventQ,-self.EventQ.EventTime)
return level:benign
|