The base clutter.Actor
has several signals that are emitted when the user interacts with the actor:
button-press-event
: Emitted when the user presses the mouse over the actor.
button-release-event
: Emitted when the user releases the mouse over the actor.
motion-event
: Emitted when the user moves the mouse over the actor.
enter-event
: Emitted when the user moves the mouse in to the actor's area.
leave-event
: Emitted when the user moves the mouse out of the actor's area.
For instance, you can detect button clicks on an actor like so:
actor.connect("button-press-event", on_rect_button_press)
Alternatively, you might just handle signals from the parent clutter.Stage
and use
stage.get_actor_at_pos
to discover which actor should be affected.
However, as a performance optimization, PyClutter does not emit all event signals by default. For instance, to
receive event signals for an actor instead of just the stage, you must call actor.set_reactive()
.
If you don't need the motion event signals (motion-event
, enter-event
and leave-event
),
you may call the global clutter.set_motion_events_enabled()
function with False
to further optimize performance.
Your event signal handler should return True
when it has fully handled the event, or False
if you want the event to be sent also
to the next actor in the event chain. PyClutter first allows the stage to handle each event via the captured-event
signal. But if the stage does not handle the
event then it will be passed down to the child actor, first passing through the actor's parent containers, giving each actor in the hierarchy a chance to handle the event via a
captured-event
signal handler.
If the event has still not been handled fully by any actor then the event will then be emitted via a specific signal (such as button-press-event
or
key-press-event
. These specific signals are emitted first from the child actor, then by its parent, passing all they way back up to the stage if no signal handler
returns true
to indicate that it has handled the event fully.
Actors usually only receive keyboard events when the actor has key focus, but you can give an actor exclusive access to any events by grabbing either the pointer or
the keyboard, using clutter.grab_pointer()
or clutter.grab_keyboard()
.
The following example demonstrates handling of clicks on an actor:
File: main.py
import sys import clutter def on_stage_button_press(stage, event): print "Clicked stage at (%f, %f)" % (event.x, event.y) # Discover whether there is an actor at that position. # Note that you can also connect directly to the actor's signals instead. rect = stage.get_actor_at_pos(clutter.PICK_ALL, int(event.x), int(event.y)) if not rect: return False if isinstance(rect, clutter.Rectangle): print " A rectangle is at that position." return True # Stop further handling of this event. def on_rect_button_press(stage, event): print "Clicked rectangle at (%f, %f)" % (event.x, event.y) # clutter.main_quit() return True # Stop further handling of this event. def on_rect_button_release(stage, event): print "Click-release on rectangle at (%f, %f)" % (event.x, event.y) return True # Stop further handling of this event. def on_rect_motion(stage, event): print "Motion in the rectangle." return True # Stop further handling of this event. def on_rect_enter(stage, event): print "Entered rectangle." return True # Stop further handling of this event. def on_rect_leave(stage, event): print "Left rectangle." return True # Stop further handling of this event. def main(): stage_color = clutter.Color(0, 0, 0, 255) label_color = clutter.Color(255, 255, 255, 153) # Get the stage and set its size and color stage = clutter.Stage() stage.set_size(200, 200) stage.set_color(stage_color) # Connect signal handlers to handle mouse clicks on the stage stage.connect('button-press-event', on_stage_button_press) # Add a rectangle to the stage rect = clutter.Rectangle(label_color) rect.set_size(100, 100) rect.set_position(50, 50) rect.show() stage.add(rect) # Allow the actor to emit events. # By default only the stage does this. rect.set_reactive(True) # Connect signal handlers for events rect.connect('button-press-event', on_rect_button_press) rect.connect('button-release-event', on_rect_button_release) rect.connect('motion-event', on_rect_motion) rect.connect('enter-event', on_rect_enter) rect.connect('leave-event', on_rect_leave) # Show the stage stage.connect('destroy', clutter.main_quit) stage.show() # Start the main loop, so we can respond to events clutter.main() return 0 if __name__ == '__main__': sys.exit(main())