VPython進階教學:按鈕
作者:王一哲
第1版:2018/7/23
第2版:2021/8/22
由於我們之前做的動畫,都是在按在 F5 後自動開始執行,如果我們想要在動畫中新增按鈕,讓使用者可以自己控制動畫,應該要怎麼做呢?我們希望按鈕的功能有:
- 執行:按下時開始執行動畫,按鈕上的文字變為 暫停;再按一下暫停動畫,按鈕上的文字變為 執行。
- 重置:按下時重置木塊的位置
- 用滑桿控制木塊的速度
我們使用最簡單的動畫〈等速度直線運動〉的程式碼來改寫,這是線上版連結,成果如下:
程式碼
from vpython import *
Web VPython 3.2
"""
1. 參數設定, 設定變數及初始值
"""
d = 10
L = 200
t = 0
dt = 0.01
re = False
running = False
"""
2. 畫面及函式設定
"""
scene = canvas(width=800, height=400, x=0, y=0, background=vec(0, 0.6, 0.6), center=vec(0, 5, 0))
scene.title = "1D Motion\n\n"
floor = box(pos=vec(0, 0, 0), size=vec(L, 0.1*d, 0.5*L), color=color.blue)
cube = box(pos=vec(0, 0.55*d, 0), size=vec(d, d, d), v=vec(0, 0, 0), color=color.red)
gd = graph(width=600, height=450, x=0, y=400, xtitle="<i>t</i> (s)", ytitle="<i>x</i> (cm)", fast=False)
gd2 = graph(width=600, height=450, x=0, y=850, xtitle="<i>t</i> (s)", ytitle="<i>v</i> (cm/s)", ymin=-6.0, ymax=6.0, fast=False)
xt = gcurve(graph=gd, color=color.red)
vt = gcurve(graph=gd2, color=color.red)
def run(b1):
global running
running = not running
if running: b1.text = "暫停"
else: b1.text = "執行"
b1 = button(text="執行", pos=scene.title_anchor, bind=run)
def reset(b2):
global re
re = not re
b2 = button(text="重置", pos=scene.title_anchor, bind=reset)
def setv(vslider):
cube.v.x = vslider.value
vtext.text = "{:1.1f} cm/s".format(vslider.value)
vslider = slider(min=-5.0, max=5.0, value=1.0, length=200, bind=setv, right=15, pos=scene.title_anchor)
vtext = wtext(text="{:1.1f} cm/s".format(vslider.value), pos=scene.title_anchor)
cube.v.x = vslider.value
def init():
global re, running, t
cube.pos = vec(0, 0.55*d, 0)
cube.v.x = vslider.value
t = 0
xt.delete()
vt.delete()
re = False
running = False
b1.text = "執行"
def update():
global t
cube.pos += cube.v*dt
xt.plot(pos=(t, cube.pos.x))
vt.plot(pos=(t, cube.v.x))
t += dt
"""
3. 主程式
"""
while True:
rate(1000)
if (cube.pos.x <= -L*0.5+d*0.5 and cube.v.x < 0) or (cube.pos.x >= L*0.5-d*0.5 and cube.v.x > 0): cube.v.x = 0
if running: update()
if re: init()
參數設定
除了一些物件的資料之外,另外設定了重置狀態re、物體運動狀態running等2個變數,預設值皆為False。
畫面及函式設定
-
先用以下的程式碼新增動畫視窗、木塊、地板。
-
設定執行按鈕b1,分為2個部分:
(1) 自訂函式run(b1),函式內使用了全域變數running,當b1被按下時,將running的狀態反過來,若原為False則改為True,若原為True則改為False;改變按鈕上的文字,若running的狀態為True則文字改為暫停,若running的狀態為False則文字改為執行。
(2) 用button產生按鈕b1,其中text為按鈕上顯示的文字,pos為按鈕位置,在此設定為scene的標題位置(scene.title_anchot),bind則是用來將這個按鈕物件連結到自訂函式run。
-
設定重置按鈕b2,分為3個部分:
(1) 自訂函式reset(b2),函式內使用了全域變數re,當b2被按下時,將re的狀態反過來,若原為False則改為True,若原為True則改為False。
(2) 用button產生按鈕b2並連結到自訂函式reset。
(3) 自訂函式init(),執行此函式時,木塊會回到初位置,清除x-t圖、v-t圖中的資料,將running設定為False,將按鈕b1的文字變為執行。
-
設定控制速度的滑桿,分為4個部分:
(1) 自訂函式setv(vslider),修改木塊的速度、滑桿右側顯示速度的文字。
(2) 用slider產生滑桿vslider並連結到自訂函式setv。
(3) 用wtext產生顯示速度的文字vtext。
(4) 設定木塊的初速度。
-
自訂函式update(),執行此函式時,更新木塊的位置,繪製x-t圖、v-t圖,更新時間。
主程式
由於我們將大部分的內容及效果寫在自訂函式中,所以主程式非常短,只有以下幾行
注意事項:rate(1000) 一定要放在 while 迴圈裡面,否則動畫無法順利執行。
- 如果木塊碰到地板左側邊緣且速度向左,或是木塊碰到地板右側邊緣且速度向右,將速度速度設定為0。
- 如果running的值為True,呼叫自訂函式update()更新狀態。
- 如果re的值為True,呼叫自訂函式init()。
執行效果
我們可以用滑桿控制木塊的速度使木塊來回移動,當木塊抵達地板邊緣時,木塊會停止移動,但是時間仍會繼續增加,這是和第1版程式最大的差異。
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
用滑桿控制木塊來回移動的x-t圖
結語
用VPython製作一個有操作界面的動畫,雖然也能做出不錯的效果,但是我們需要花較多的時間寫程式,用來處理物理模型的時間相對上較少,所以我們只簡單地做了這個動畫,之後的課程還是以處理物理模型為主。如果對於VPython的按鈕、滑桿、選單、核取方塊……等元件的用法有興趣,請參考GlowScript網站上的範例自行改寫。
參考資料
- VPython官方說明書Widgets: http://www.glowscript.org/docs/VPythonDocs/controls.html
- GlowScript網站範例Buttons Sliders Menus: http://www.glowscript.org/#/user/GlowScriptDemos/folder/Examples/program/ButtonsSlidersMenus-VPython