Events
Relevant Logic icon

Relevant Logic


Events

What follows is an excerpt from the Book.

When you open a class for editing in REALbasic, something you may see is one or more Event Handlers:

Figure 32: The Event Handlers for a Window

How these Event Handlers appear is this: a class can contain an Event Definition, which is essentially half a method definition: defining an Event defines something like a method that its subclasses have the opportunity to implement. An Event Definition in a class immediately results in all subclasses showing a corresponding Event Handler, which represents that opportunity to act.

Once a class defines an Event, that class can call the event just like a method call, except you put the keyword RaiseEvent in front of it. The most immediate subclass that provides code in its corresponding Event Handler will have that code invoked when the superclass calls the Event.

Note that once you provide an Event Handler in ClassB for an event in its superclass, ClassA, any further subclasses of ClassB won't even show the Event Handler. This is reasonable, since there is no way for the Event Handler in the further subclass to be invoked. However, ClassB is free to provide an Event Definition with the same arguments (and return type, if it's a function) as the original, and to call it in turn, thus effectively propagating the event down the inheritance chain. This is a normal and natural way to use Event Handlers in REALbasic.

A few notes before we look at an example.

The REALbasic documentation implies that Event Handlers are only for use with subclasses of Controls. Not so. You can and should use Event Handlers across any classes you create.

Otherwise unhandled Events issued by controls can also be handled by code in a Window, by placing an instance of the control in the Window, and putting code in the Event Handlers for the control in the Window's code editor. This is a good way of dealing with the specifics of what a particular control instance should do in a particular window.

Also, you may be wondering what happens if a class calls an event handler, but either it has no subclasses, or none of its subclasses provide a handler for the event. The answer is: if the Event is a regular method, nothing happens. If the Event is a function, Nil, 0, False or the empty string is returned. As we will see, you can sometimes rely on this to detect whether a subclass provides a handler.

Event Handler Example

As an example of using Events, we will look at a classic example: creating an EditField subclass that restricts what the user can enter (in this case, it will only let the user enter numbers). We will do this by adding suitable code to the KeyDown Event Handler for an EditField subclass.

  1. Create a new REALbasic project.

  2. Add a new class. Name it NumEdit, and set its Super to EditField.

  3. Double-click on the class to open its editor pane, expand the Event Handlers section, and click on the KeyDown Event Handler. Enter the following code:

Figure 33: Code for the NumEdit.KeyDown EventHandler

This works because of the way the KeyDown event works: it is a Boolean function—if the function returns False (note that this is what happens when the subclass doesn't provide an Event Handler), the keystroke is accepted, but if it returns True, the keystroke is ignored.

  1. Add the new class to the default Window (you can drag an EditField into the window and then change its Super), run the project and try it out. Then put a breakpoint at the top of the KeyDown Event Handler, and try it again.

  2. Next, we will explore the use of a chain of subclasses, delegating authority down the chain through a series of identical Event Handlers. Note that the above code won't really support such a chain (at least for KeyDown); we will have to modify it so our Event Handler calls an identical Event. We have to decide how this delegation will work: will a subclass be able to allow some keystrokes in that NumEdit wants to reject, or will it only be able to reject some of the keystrokes that NumEdit wants to accept? Or both? We will do the second case: a subclass will only be consulted if NumEdit is disposed to accept a keystroke. We will implement a further subclass that will only let the user enter numbers below a certain value.

  3. Add a New Event to NumEdit with the same signature as the original KeyDown:

Figure 34: Add a new KeyDown Event

And change the original Event Handler so that rather than just return False, we return whatever we get back from the New Event:

Figure 35: The KeyDown Event Handler, now delegating to a similar Event

Note that if there is no subclass, the call to the Event will return False, so this Event Handler will just be returning False in that case. So we can still use an instance of our NumEdit class as before.

  1. Now, create a new subclass of NumEdit (the easiest way to do this is to control- or right-click on NumEdit in the Project pane, and choose New Subclass from the menu). Name the new subclass something like LimitNumEdit.

  2. Add a Maximum as Integer property, and the following KeyDown event handler:

Figure 36: The KeyDown Event Handler in the subclass

The new event handler tests what the string—with the new keystroke inserted—would be as a number, and rejects it if it would be over the Maximum property's value.

  1. Speaking of which, we need to add a Maximum property, so do that.

  2. Change the Super of the NumEdit in the window to LimitNumEdit. And in the window's Open Event Handler, set its Maximum to, say, 500.

  3. Run the result, and try it out, with and without a breakpoint in the NumEdit class's KeyDown Event Handler

Note how the NumEdit class had complete control over how further subclasses can extend it. It could, for example, have invented new Events (perhaps it could have AlphaKeyDown and NumKeyDown Events) instead of, or as well as, KeyDown. We will discuss how to design with Events in the next chapter.

blog comments powered by Disqus