Client Event Handling
From Multiverse
| User Interface Development |
|
Overview • Managing Widgets • Event Handling • Using Widget Templates • Customizing Key Bindings • Localizing UI Text • Character Creation Framework • Minimap Component • Scripting Avatar Appearance |
| Reference |
| Tutorials |
|
Hello World • Creating a Button • Creating a Menu • Creating a Help Dialog • Using Radio Buttons |
Contents |
Overview
You add behavior to UI elements defined in XML files with Python scripts. There are two ways to attach Python scripts to UI elements:
- Embed short scripts directly in the XML files within an event handler element.
- Put long scripts in a separate Python (
.py)file, included via a Script element.
To include Python code in an external file, use one or more <Script> elements at the start of the XML file. For example:
<Ui> <Script file="mycode.py"/> <Frame name="MyFrame"> ... </Frame> </Ui>
In the above example, when the Multiverse client reads the XML file,
it reads and interprets the contents of the mycode.py file. The
code in that file is then available for the rest of this XML file, and any
XML files that the client subsequently reads. Functions defined in mycode.py can
be called from event handlers in the XML file.
Basic event handling concepts
A traditional procedural program has a beginning and an end. Execution starts at the beginning, and follows the algorithm in the program to the end, when the program terminates. In contrast, an event-driven program has independent sections of code with no overall start or finish. Each of these sections of code is designed to execute in response to a certain event occuring. Such a section of code is called an event handler. An event handler may get executed once, many times, or never, depending on what the user does.
Events
Events are messages sent by the Multiverse client to event-handling scripts. To receive an event, you must:
- Register the event for the object with the following code
object.RegisterEvent( nameOfEvent )
- Create an <OnEvent> handler for the object. The <OnEvent> handler receives a variable named
eventwhich contains the name of the event.
It also receives args which contains additional information regarding the event. To unregister an event, use the following code:
object.UnregisterEvent( nameOfEvent )
Handling UI events
Event handler code responds to UI events. Use the <Scripts> element to include Python event handler code in an XML file. The <Scripts> element can contain one or more <OnEventName> event handler elements, where EventName is the name of the event. For example, <OnLoad>, <OnMouseDown>, and so on, as shown below:
<Frame name="MyFrame">
<Scripts language="python">
<OnShow> message("Hello!") </OnShow>
</Scripts>
</Frame>
In the above example, the frame has one event handler, OnShow, which is executed
every time the Frame becomes visible. The contents of the OnShow element can
be any valid Python code. In this example, it's a single statement that calls the function message(),
which displays a dialog box containing the text "Hello!"
Here is a more complete example of how you include Python code and then reference
it from the event handlers.
The file myframe.xml looks like this:
<Ui>
<Script file="myframe.py"/>
<Frame name="MyFrame">
<Scripts language="python">
<OnLoad> ShowMessage() </Onload>
</Scripts>
</Frame>
</Ui>
The Python code in myframe.py looks like this:
def ShowMessage():
message("Hello World!")
When the client loads myframe.xml, it executes the OnLoad event handler.
In this case, the single Python statement there simply calls the ShowMessage() function defined in myframe.py, which displays the message "Hello World!"
The OnEvent handler
The OnEvent handler is special. Most event handlers are triggered when a particular UI event occurs, such as clicking on a Button widget. The OnEvent handler is special because it is a general, collective handler that is triggered when any event occurs.
Here is an example of a frame that registers for a property event, and has a handler that prints information about that event.
The file myframe.xml looks like this:
<Ui>
<Script file="myframe.py"/>
<Frame name="MyFrame">
<Scripts language="python">
<OnLoad>this.RegisterEvent('PROPERTY_HEALTH_UPDATE')</Onload>
<OnEvent>DisplayHealthUpdate(this, args)</OnEvent>
</Scripts>
</Frame>
</Ui>
The Python code in myframe.py looks like this:
def DisplayHealthUpdate(obj, event):
# note that if the event was about the player and the target, we will be called
# three times (once for player, once for target, and once for any)
ClientAPI.LogInfo('Got event: %s' % event.eventType)
if event.eventArgs[0] == 'player':
# this is info about the player
# if we were the player's health bar, we would care
ClientAPI.Write('Your health was updated')
if event.eventArgs[0] == 'target':
# info about the target (may also be the player)
# if we were the target bar, we would care
ClientAPI.Write('The health of your target was updated')
if event.eventArgs[0] == 'any':
# we always get this when the property changes
# we might use this if we were a health bar widget for a group member
ClientAPI.Write('Got health update for object with OID: %d' % long(event.eventArgs[1]))
Event handler arguments
The arguments you pass to an event handler depend on the specific event being handled.
- OnEvent (GenericEventHandler) - The event argument has an eventType field that is a string, and an eventArgs field that is an array of strings.
- OnMouseWheel (FloatEventHandler) - The event argument has a data field that is a float.
- OnChar (KeyboardEventHandler) - The event argument has a keyboard event object, which contains information about the key pressed.
- OnDoubleClick (MouseEventHandler) - The event argument has a mouse event object, which contains information about the current mouse position, and relative offset. This may be None if the event was not triggered by a mouse event.
- OnScrollRangeChanged (ExtendedEventHandler) - The event argument has a data field that is an array of objects
Events not called by the input handler
Some event handlers (identified in the Widget Reference with the note "Not called by the input handler") can be attached to widgets, but are not automatically called by the Client. For example, you can create and call an OnSizeChanged event handler, but it will not be automatically called when the widget's size is changed. You must call the event handler yourself based on some other UI action.
