
Lesson 8 - Events
In this lesson we look at mouse and keyboard events and how VPython reports them.
Objectives
By the end of the lesson the student should be able to:
- Understand how create a label containing text.
- Understand how to detect keyboard and mouse events.
- Understand how to define a function.
- Understand how to bind a function to an event.
- Understand how to bind an event to an object through a function.
- How to look for multiple keys being down.
Timings
Teaching: 40 min
Exercises: 20 min
Description
Glowscript VPython can detect many mouse and keyboard events:
mousedown
mouseup
mouseclick
mouseleave
mouseenter
mousemove
keydown
keyup
keypress
Note: There is currently no way in GlowScript to handle right button or middle button events.
Events in VPython are controlled by scene.
The scene is everything within the graphics window which is not a shape, such as the width and height of the graphics window,
the background colour and lighting, the camera position and the degree of zoom.
Lesson 11 will look at the scene in more detail.
The program
The code below displays two labels which are updated through keyboard and mouse events.
# Define two labels with default texts
txt = label(pos=vector(0,6,0), text='No keys pressed', align='center',height=36, color=color.green)
txt2 = label(pos=vector(0,-3,0), text='Nothing pressed', align='center',height=36, color=color.green)
# Define a function that is called when a key or mouse is pressed
def getevent(ev):
k = keysdown() # a list of keys that are down
#Define an "if" statement to 'look for' mouse events
if ev.event == 'mousedown':
txt.text='You mousedowned at\n' + ev.pos
txt.color=color.yellow
else if ev.event == 'mouseup':
txt.text='Nothing clicked'
txt.color=color.red
#Define an "if" statement to 'look for' keyboard events
txt2.text='You are holding down\n' + k
else if ev.event == 'keydown':
txt.text='You pressed\n' + ev.key
txt.color=color.red
txt2.text='You are holding down\n' + k
#Define an "if" statement to 'look for' key events and reset text label back to default
if ev.event == 'keyup':
txt.text='No keys pressed'
txt2.text='Nothing pressed'
txt2.color=color.green
#Tell the "scene" to use the getevent function whenever a key or mouse is pressed
scene.bind("mousedown", getevent)
scene.bind("mouseup", getevent)
scene.bind("keydown", getevent)
scene.bind("keyup", getevent)
#Tell the "scene" which events to respond to
scene.waitfor('mousedown mouseup keydown keyup ')
Things to note
The last line of the program asks the scene to wait for the specified events.
A function getevent(ev) is defined and it is bound to the event by the scene.bind() method.
Now when the scene is clicked or a key is pressed, the getevent function is fired. When it is fired it passes the event data to the function via the ev variable.
VPython keeps track of which keys are down using the keysdown() function, which returns a list of all the keys which are pressed.
The getevent function then filters the event recieved and alters the text in the label accordingly.
The ev variable in getevent is user defined. For example it could be 'e' or 'evt' or 'zxpw', but will contain the event data.
Essentially think of the ev variable as a place where VPython 'puts' the details of the event.
Here we use ev.event and ev.key, but there are more, such as ev.type, ev.ctrl, ev.shift,
ev.alt and ev.which.
Note: Keys with multiletter names are 'backspace', 'caps lock', 'tab', 'shift', 'ctrl', 'alt', 'pageup', 'pagedown', 'end', 'home', 'left', 'up', 'right', 'down', 'insert', 'delete', 'break', and the function keys 'f1' through 'f10'.
Exercise 1
Copy the program above and do the following:
Modify the program to make the word 'HELLO!' appear in the bottom label in magenta, when the user presses 'ctrl'+ 'alt' + shift.
# Define two labels with default textsSolution to Exercise 1
txt = label(pos=vector(0,6,0), text='No keys pressed', align='center',height=36, color=color.green)
txt2 = label(pos=vector(0,-3,0), text='Nothing pressed', align='center',height=36, color=color.green)
# Define a function that is called when a key or mouse is pressed
def getevent(ev):
k = keysdown() # a list of keys that are down
#Define an "if" statement to 'look for' mouse events
if ev.event == 'mousedown':
txt.text='You mousedowned at\n' + ev.pos
txt.color=color.yellow
else if ev.event == 'mouseup':
txt.text='Nothing clicked'
txt.color=color.red
txt2.text='You are holding down\n' + k
#Define an "if" statement to 'look for' keyboard events
else if ev.event == 'keydown':
txt.text='You pressed\n' + ev.key
txt.color=color.red
txt2.text='You are holding down\n' + k
#Define an "if" statement to 'look for' ctrl, alt and shift keys
if'ctrl' in k and 'alt' in k and 'shift' in k: # solution
txt2.text='HELLO!'
txt2.color=color.magenta
else:
txt2.text='You are holding down\n' + k
#Define an "if" statement to 'look for' key events and reset text label back to default
if ev.event == 'keyup':
txt.text='No keys pressed'
txt2.text='Nothing pressed'
txt2.color=color.green
#Tell the "scene" to use the getevent function whenever a key or mouse is pressed
scene.bind("mousedown", getevent)
scene.bind("mouseup", getevent)
scene.bind("keydown", getevent)
scene.bind("keyup", getevent)
#Tell the "scene" which events to respond to
scene.waitfor('mousedown mouseup keydown keyup ')
Conclusion
You should now be able to:
Create a label containing text.
Detect keyboard and mouse events.
Define a function.
Bind a function to an event.
Bind an event to an object through a function.
Look for multiple keys being down.