#

這一個章節的目標是把播放清單的功能加進iPlayer,程式的重點在於::ttk::treeview運用,所以在讀完這個章節後,你應會更了解treeview的運用時機。另外,在章節的後半段也示範了狀態控制的程式。

23.1 加入清單方塊

接下來我們要先在gui_init程序中增加「加入MP3」及「播放清單」的視窗元件,分別是使用button及treeview完成,程式碼如下:



大家應該有發現這個程序的一開頭引入了Priv變數,我們之前並沒有宣告它,怎麼突然多出來了? 其實是這樣的:習慣上我會為每一個自己建立的名稱空間建立一個名為Priv的名稱空間變數,而且它是一個陣列的結構,然後我會把這個名稱空間裡公用的資訊都放在裡面,這樣做的好處是不用宣告一堆變數,維持程式的簡潔。以這邊的情況來看清單方塊的path會在pl_add程序(還沒實作我知道的)被使用到,所我們要把清單方塊的path儲存進Priv陣列裡,這樣pl_add裡才可以控制清單方塊。當然為了要讓這個陣列可以使用,還是要先建立它:



完成後請執行程式,畫面像這樣:

圖 23-1


□ 加入MP3檔案

現在我們要處理還沒有實作的pl_add程序。這個程序的功能很單純,首先它在執行時應該跳出一個選擇資料夾的對話方塊,並請使用者選擇一個包含MP3檔案的資料夾。當使用者選好資料夾以後,再把所有的MP3檔案掃進播放清單。



這個程式的中間使用到了$Priv(pl),還記得我們在gui_init的最後一行有把清單方塊的path儲存在裡面吧!!現在大家自己試試這個功能。

圖 23-2


23.2 修改play程序

現在我們已經有播放清單了,所以下面這一行已經不再需要,所以請刪掉它。



接下來我們要稍微修改play程序,讓它可以由播放清單中挑選檔案播放。play程序的邏輯如下:

  1. 查看播放清單,如果是空的就離開目前的程序,否則就往下執行。
  2. 取得目前清單方塊中選中的檔案,如果沒有選中的檔案那就選第1個。
  3. 播放剛剛挑選的檔案。

這個邏輯實作出來的程式如下:



自己試試看吧!!

23.3 狀態控制

目前我們已經有一個看似沒問題的播放清單了,不過是不是真的沒問題呢? 請試試下面的操作,看有什麼不對勁的地方。

  1. 先在清放清單中選擇一首MP3然後按下播放。
  2. 播放到一半時,按下暫停(不是停止哦)。
  3. 在播放清單中隨便點另一首MP3,然後再按下播放。

照上面的情況來說,我們希望程式會繼續播第一首MP3對吧!! 因為我們是按暫停,不是停止,但沒想到...執行的結果居然是播新選中的MP3,怎麼會這樣呢? 其實這是必然的結果,因為目前的play程序總是會播放選中的項目,程式就是這樣寫的。

如果要解決上面發生的問題,我們必需讓程式可以處理播放的狀態,也就是說程式要記下當前的狀態,並在不同的狀態下鎖住或是允許某些功能,例如:在暫停狀態按下播放按鈕要繼續上一首MP3,而不是挑新的MP3播放。

為了可以記住目前的播放狀態,我們需要在Priv裡加入一個專門用來記錄播放狀態的元素,然後在程式一啟動時把狀態設定為「STOP」。以後在執行各個播放功能時也要適時的改變這個元素的值。修改後的init程序如下:



注意哦!! 初始化時播放狀態設定為「STOP」,是個合理的假設!!

修改後的pause程序如下:



在pause的程序裡,我們要保證暫停的動作只能在「PLAY」狀態下執行,所以pause程序的一開頭要加入條件式:「目前的狀態不是PLAY離開程序」。然後程式的最後面我把目前的狀態切換為「PAUSE」,因為上一行播放器被暫停了。

然後是修改後的stop程序:



stop算是最單純的,因為任何情況下按停止,都要回到停止狀態。

最後是修改後的play程序:



這個程序改得比較多,在程序的開頭多一個條件式,它用來判斷如果目前的狀態是PAUSE就繼續播放上一次的MP3,然後離開程序。另外在程序的最後面也加上了切換狀態的程式。

Ok!! 請再執行程式,沒意外的話剛剛的問題應該處理好了。

23.4 美化播放清單

我想大家應該都有發現一個問題「播放清單很醜」,是的播放清單應該顯示MP3的主檔名就好了,路徑及副檔名不要顯示會較美觀。不過這個功能會產生另一個問題「如果播放清單只記錄主檔名而不是完整路徑,那麼程式怎麼知道MP3檔案是放在哪裡?」。 為了決解這個問題,程式中勢必要儲存播放清單個項目及MP3完整路徑的對應關係。在這邊我打算用一個陣列來記錄這些資訊,因為像這種類似對照表的資訊,用陣列來儲存是很適合的。下列的程式在名稱空間裡建立一個陣列pathTbl,用它來儲存上述的對照資訊:



當然pl_add程序也要做一點小修改。



請先注意到把MP3加下清單方塊的那一行,$mp3裡儲存的是完整的路徑,我先用file tail去掉路徑的部份,然後再用file rootname去掉副檔名的部份,所以兩次代換的結果就只剩下主檔名了。接下來的一行,很單純的用陣列來記錄項目與完整路徑的對應關係。

雖然有點麻煩,但play程序還要改一個小地方。請找到下面的程式片段:



現在播放清單中不會再有醜醜的路徑了。

圖 23-3


23.5 最後的小修改

最後我們要讓這個程式好操作些。如果使用者在播放清單上按滑鼠兩下就讓他直接播放音樂。 這項功能只需要修改init程序就可以辦得到。



這邊是我們第二次看到bind命令,關於它以後會有特別的章節說明,目前先不要太在意它就先這樣用。

接下來還有一個「清除播放清單」的功能需要加入。實現這個功能的程序如下:



當然上面的程序還要配合一個「清除的按鈕」才會發生效用,這邊就先不把程式寫出來了,賣個關子請大家自己多寫一個「清除按鈕」的功能吧!! 不過如果懶得想的話,還是可以參考最下方的程式,裡面已經寫好了。

23.6 程式資源

如果你打的程式跑不出來的話,可以這在邊下載我打的程式iPlayer.tcl

另外下面是這個程式會用到的圖片,請自己另存新檔。 注意哦!! 這些圖片要和iPlayer.tcl放在同一個資料夾裡面。

6 個意見

匿名 | 2010年6月3日 下午6:12

大大
副程序 proc gui_init 裡少了一行 variable Priv 喔

為了這行小弟我苦惱了一個下午呢

謝謝喔

dai | 2010年6月4日 凌晨12:14

hi..謝謝你的通知~~ 

但我找不到哪裡沒加 @@

是本頁的第一個程式嗎? 第2行有加variable Priv

還是說在其它地方我沒看到?

Unknown | 2015年1月20日 下午2:46

作者已經移除這則留言。

Unknown | 2015年1月20日 下午2:47

作者已經移除這則留言。

Unknown | 2015年1月20日 下午2:48

大大請問一下
set fme [::ttk::frame .fmeCtrl]
set btnPlay [::ttk::button $fme.btnPlay -text "play" -command {::iPlayer::play} ]


::ttk::frame .fmeCtrl
::ttk::button .fmeCtrl.btnPlay -text "play" -command {::iPlayer::play}

這兩種寫法有甚麼不同嗎?

匿名 | 2015年1月20日 下午3:40

$fme可以比.fmeCtrl少打幾個字,若程式需要修改時,前者的方法要改的地方也比較少

留下您的意見

Theme Design by devolux.org. Converted by Wordpress To Blogger for WP Blogger Themes. Sponsored by iBlogtoBlog
This template is brought to you by : allblogtools.com | Blogger Templates