Home

If you're new to Python
and VPython: Introduction

A VPython tutorial

Introductory Videos

Pictures of 3D objects

What's new

Classic VPython web site
VPython license
Python web site

 

Drag Example

Here is the sequence of mouse events involved in dragging something:

1) Determine that the mouse button has been depressed (a mousedown event).

2) Continually watch for the mouse to move, and use scene.mouse.pos to update positions. These are mousemove events.

3) Conclude the drag when the mouse button has been released (a mouseup event).

The way you detect these mouse events is by writing functions that are bound to the mouse events using scene.bind, and GlowScript will execute these functions when these mouse events occur.

Here is a complete routine for repeatedly creating and dragging a sphere, so that you can arrange many spheres on the screen. While being dragged the sphere is red, but its color changes to cyan when the mouse button is released.

scene.range = 5
box()

drag = False
s = None # declare s to be used below

def down():
    nonlocal drag, s
    s = sphere(pos=scene.mouse.pos,
        color=color.red,
        size=0.2*vec(1,1,1))
    drag = True

def move():
    nonlocal drag, s
    if drag: # mouse button is down
        s.pos = scene.mouse.pos

def up():
    nonlocal drag, s
    s.color = color.cyan
    drag = False

scene.bind("mousedown", down)

scene.bind("mousemove", move)

scene.bind("mouseup", up)

It is also possible to use "anonymous" (unnamed) functions, an extended feature of the RapydScript Python-to-JavaScript compiler, as shown here:

scene.range = 5
box()

drag = False
s = None # declare s to be used below

scene.bind("mousedown", def ():
    nonlocal drag, s
    s = sphere(pos=scene.mouse.pos,
               color=color.red,
               size=0.2*vec(1,1,1))
    drag = True
)

scene.bind("mousemove", def ():
    nonlocal drag, s
    if drag: # mouse button is down
        s.pos = scene.mouse.pos
)

scene.bind("mouseup", def ():
    nonlocal drag, s
    s.color = color.cyan
    drag = False
)

 

Other mouse events: You can also watch for mouseenter (the mouse is moved from the outside of the canvas to the inside), mouseleave (the mouse leaves the canvas), and click.

Multiple event types: You can bind a function to more than one type of event. Here is a function bound to both mousedown and mouseup events, either of which will cause a sphere to be created:

scene.bind("mousedown mouseup", def ():
    sphere(pos=scene.mouse.pos)
)

Unbinding: After binding a function to a mouse event, you can unbind the function, in which case GlowScript will no longer send events to your function. In the program shown above, if you place scene.unbind("mousedown") in the mouseup event, you will be able to drag just one sphere.

Just one: If you use scene.one instead of scene.bind, the binding occurs for just one event and then is automatically unbound. In the program shown above, if you specify scene.one for the mousedown event, you will be able to drag just one sphere.

Custom events: You can set up your own custom events using scene.trigger. In the following sample program, first you see a box, then the while loop halts waiting for the custom "ball" event to occur. When you click, the "click" function is executed, and in the click function a sphere is created and a new type of event, "ball", is triggered by scene.trigger, with optional argument newball = s. With this triggering of a "ball" event, the "ball" function receives the triggered arguments in ev and sets the sphere's color to blue. The triggering of the "ball" function also breaks through the scene.waitfor in the while loop that was waiting for a "ball" event. The scene.waitfor statement returns the entity that was sent to the "ball" function, and uses the sphere's position to reposition the box. The process in the loop then repeats.

scene.bind("click", def ():
    s = sphere(pos=scene.mouse.pos)
    scene.trigger("ball", newball=s)
)

scene.bind("ball", def (ev):
    ev.newball.color = color.blue
)

b = box()

while True:
    ss = scene.waitfor("ball")
    b.pos = ss.newball.pos + vec(0,-1, 0)