Home

   Overview of Python & VPython

  "Welcome to VPython" tutorial

  Introductory Videos

  Pictures of 3D objects

  

  

  

  VPython 7 web site
  VPython license

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 Web VPython 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():
    global drag, s
    s = sphere(pos=scene.mouse.pos,
        color=color.red,
        size=0.2*vec(1,1,1))
    drag = True

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

def up():
    global 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-NG Python-to-JavaScript compiler, as shown here (this will NOT work with installed Python):

scene.range = 5
box()

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

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

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

scene.bind("mouseup", def ():
    global 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 Web VPython 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 function t is executed, and in this function a sphere is created and a new type of event, "ball", is triggered by scene.trigger, with the optional argument b, representing the new sphere. With this triggering of a "ball" event, function f receives the triggered arguments in ev and sets the sphere's color to blue. The triggering of a "ball" event also breaks through the scene.waitfor in the while loop that was waiting for a "ball" event. The process in the loop then repeats.

def t():
    b = sphere(pos=scene.mouse.pos, radius=0.2)
    scene.trigger("ball", b)
scene.bind("click", t)

def f(ev):
    # ev.type is "ball"; ev.event is newball
    ev.event.color = color.blue
scene.bind("ball", f)

cube = box(pos=vec(-2,0,0))
while True:
    s = scene.waitfor("ball")
    print(s.type, s.event.pos) # "ball" and the new sphere's pos
    cube.rotate(angle=0.1, axis=vec(0,0,1))