這一個章節我們要完成的功能稍微多一點,分別是音量控制、自動播放下一首及循環播放的功能。另外這個章節也會對核取方塊做一些簡單的介紹。
25.1 自動播放下一首
目前的iPlayer播放完當前的MP3,並不會自動播放下一首。這一小節我們要把這項功能加進去。在開始之前先來補充一個聲音物件的選項,請看下方的程式:$snd play -command {::iPlayer::next} |
其實聲音物件在執行play功能時,可以讓我們加上-command選項,放在這個選項之後的程式會在目前這首MP3播完時被執行。嗯~所以說,自動播放下一首的功能可以寫在這裡。其原理是目前這首MP3播完的時候,從播放清單找到下一首MP3來播放就可以了。現在先讓我們要先修改play及seek程序,讓聲音物件在播放完成時會執行next程序(等等就會實作了)。
#以下是修正後的play程序 proc play {} { ....以上的程式就不顯示了 # 如果目前的狀態是 PAUSE if {$Priv(State) == "PAUSE"} { #========================================注意這邊!! # 繼續播放 $snd play -command {::iPlayer::next} #======================================== # 切換狀態為 PLAY set Priv(State) "PLAY" # 啟動timer ::iPlayer::timer return } ....這邊的程式就不顯示了 # 載入新的MP3 $snd configure -file $currentFile # 設定拉桿的 上/下 邊界值及目前值 $Priv(prg) configure -value 0 -from 0 -to [$snd length -unit sec] #========================================注意這邊!! # 開始播放 $snd play -command {::iPlayer::next} #======================================== # 切換狀態為 PLAY set Priv(State) "PLAY" # 啟動timer ::iPlayer::timer } #以下是seek修正後的程序 proc seek {} { ....以上的程式就不顯示了 # 先停止播放 $snd stop #========================================注意這邊!! # 由指定的位置(sample)播放 # 由於-start只能接受整數,所以這邊用expr的int函數來確保$pos的值是整數 $snd play -start [expr int ($pos)] -command {::iPlayer::next} #======================================== # 重新啟動timer程序 after 1000 ::iPlayer::timer } |
大家還記得嗎? play程序會播放清單中被選中的項目。所以next程序的工作就是由清單中選取下一個項目,然後再重新執行play程序。
proc next {} { variable snd variable Priv #先把目前的狀態切為STOP set Priv(State) "STOP" #取得目前播放清單被選中的項目 set currItem [$Priv(pl) selection] #找出目前項目的下一個項目 set nextItem [$Priv(pl) next $currItem] #如果下一個項目是空字串,就表示目前的項目已經是最後一個了 if {$nextItem == ""} {return} #把下一個項目設定為選取中的狀態 $Priv(pl) selection set $nextItem #1秒後開始播放下一首MP3 #注意哦!!1秒的延遲是必要的,因為我們要先讓timer自己停止,然後再重新播放 after 1000 ::iPlayer::play } |
Ok!! 自動播放下一首的功能完成了,請大家自己試試吧!!
25.2 循環播放製作
循環播放指的是播完清單中的最後一首MP3之後,程式要可以重頭開始播放。這個功能我打算配合核取方塊這個視窗元件來完成,這樣一來可以順便介紹一下核取方塊。核取方塊的外觀如下:圖 25-1
使用者可以在核取方塊上打勾表示選中某項東西。在這裡我打算讓使用者透過打勾來決定是否要循環播放清單。
核取方塊
核取方塊的建立及使用滿固定的,下方的程式大概就可以滿足大部分的應用:set ::value 1 ttk::checkbutton .chk -text "打勾吧!!" -variable ::value -onvalue 1 -offvalue 0 pack .chk |
上面的程式會建出1個核取方塊,預設它會被勾上。第1行建立了一個全域變數,我打算用它來儲存核取的狀態,也就是說使用者勾選或是沒勾選的狀態會立即反映在這個變數上。接下來是第2行,-text用來指定核取方塊後面要顯示的文字,-variable就如同entry的-textvariable選項一樣,其後必需放置一個變數的名稱,此變數會反映使用者的勾選狀態,-onvalue後指定的值會在方塊被勾選時儲存在::value變數裡,-offvalue後指定的值會在方塊未勾選時儲存在::value變數裡。
□ 制作循環播放核取方塊
現在我們可以幫iPlayer加上循環播放的核取方塊了,當然用來記錄方塊的核取狀態的變數也是不能少的,這幾項工作要在gui_init裡完成:proc gui_init {} { ...以上的程式內容就不顯示了 # 建立一個框架準備用來擺放拉桿 set fme [::ttk::frame .fmePrg] pack $fme -expand 0 -fill x # 建立播放進度用的拉桿視窗元件 set prg [::ttk::scale $fme.sclPrg] pack $prg -expand 1 -fill both -side left #============================================注意這邊!! # 建立控制循環播放的核取方塊 set Priv(loop) 0 set chk [::ttk::checkbutton $fme.chkLoop -text "循環" -onvalue 1 -offvalue 0 -variable ::iPlayer::Priv(loop) ] pack $chk -fill x -side left #============================================ # 把拉桿綁定「滑鼠左鍵放開事件」 bind $prg <ButtonRelease-1> {::iPlayer::seek} # 把拉桿綁定「滑鼠左鍵下壓事件」 bind $prg <ButtonPress-1> {after cancel ::iPlayer::timer } # 拉桿視窗元件在其它程序會被用到,所以記下它的path set Priv(prg) $prg } |
測試一下iPlayer應該已經加上核取方塊了:
圖 25-2
為了要讓循環播放能夠正確的執行,我們還要稍微對next程序加以修改:
proc next {} { variable snd variable Priv #先把目前的狀態切為STOP set Priv(State) "STOP" #取得目前播放清單被選中的項目 set currItem [$Priv(pl) selection] #找出目前項目的下一個項目 set nextItem [$Priv(pl) next $currItem] #========================================================= 注意這邊!! #如果下一個項目是空字串,就表示目前的項目已經是最後一個了 if {$nextItem == ""} { # 如果沒有勾選循環播放就離開程序 if {$Priv(loop) == 0} { #離開前要先把播放進度的拉桿歸回原點 $Priv(prg) configure -value 0 return } # 取出清單方塊根項目下所有的子項目(即所有已加入的MP3檔案) set allItems [$Priv(pl) children {}] # 取出清單方塊中的第一個項目,設定為選取中的狀態 $Priv(pl) selection set [lindex $allItems 0] } else { #把下一個項目設定為選取中的狀態 $Priv(pl) selection set $nextItem } #========================================================= #1秒後開始播放下一首MP3 #注意哦!!1秒的延遲是必要的,因為我們要先讓timer自己停止,然後再重新播放 after 1000 ::iPlayer::play } |
修改的部份很單純,若$nextItem為空字串的話,表示目前已經播完清單中的最後一首,然後程式要判斷如果核取方塊沒有被勾選,就離開程序,否則的話往下執行,接下來的程式就是選第一首播放。好了,到目前為止循環播放的功能完成了,請自己試試吧!!
25.3 音量控制
用snack套件來控制音量是一件很簡單的事,下面是一個簡單的例子它會印出目前的音量百分比:puts [::snack::audio play_gain] |
如果要設定音量的話,可以像下面這樣做,這個例子會把音量大小調整為85%:
::snack::audio play_gain 85 |
加上音量控制器
了解音量控制的方法後,現在可以為iPlayer加上音量控制器了。如下請先在gui_init程序中建立一個滑桿元件來控制音量:proc gui_init {} { variable Priv ...以上的程式內容就不顯示了 # 清除播放單清按鈕 set btnPlClear [::ttk::button $fme.btnPlClear \ -image [image create photo -file "pl_clear.gif"] \ -command {::iPlayer::pl_clear} \ ] pack $btnPlClear -side left #================================================ 注意這邊!! # 建立控制音量的拉桿視窗元件 set vol [::ttk::scale $fme.sclVol \ -from 0 \ -to 100 \ -value [::snack::audio play_gain] \ -command {::iPlayer::volume}] pack $vol -expand 1 -fill both -side left #================================================ # 建立一個框架元件,把清單方塊及捲軸方塊放在裡面,以方便管理 set fmePl [::ttk::frame .fmePl] pack $fmePl -expand 1 -fill both # 建立一個可以顯示清單的treeview視窗元件 set pl [::ttk::treeview $fmePl.pl -show tree] ...以下的程式內容就不顯示了 } |
在建立滑桿時我先把目前的音量設定給滑桿的-value選項當做拉桿的初始值。另外我也指定了滑桿的-command選項是::iPlayer::volume,意思是每次拉桿上的按鈕滑動時都會執行volume程序,而volume程序如下:
#控制音量的程序 proc volume {vol} { ::snack::audio play_gain [expr int($vol)] } |
由於play_gain只能接受整數值,所以我們要先用expr的int函數把$val的值轉為整數,再設定給play_gain。完成了請大家自己試試吧!!
圖 25-3
25.4 程式資源
在這邊可以下載到目前已完成的程式 - iPlayer.zip。按右上方的「#」號切換側邊欄