這一個章節將完成iPlayer的最後兩個功能,分別是「自動儲存播放清單」及「自動載入播放清單」,這兩個功能指的是每當有新的MP3加入播放清單時,iPlayer就會自動的把播放清單的內容儲存一份在硬碟裡面,當然的等到下次再重新啟動iPlayer時,我們就可以把之前的播放清單內容由硬碟裡載回來。如此,就不用每次啟動iPlayer時還要重加播放清單的內容了。
26.1 儲存播放清單的位置
其實播放清單儲存的位置,是一個可以好好考慮的問題。我們先假設這份播放清單是一件很重要的設定檔,如果隨便找到地方儲存,也許哪天重灌電腦時就很有可能會忘了備份他。另外,對於一些有系統潔癖的人來說,隨意的在磁碟裡留下一些檔案,也是非常不可以接受的事。那到底要儲存在哪裡才是適當的呢? 如果玩過Linux或Mac的朋友,那有很大的機會你會遵守「儲存在家目錄」的規則,事實上這可能是最好的方法。但對於在Windows上開發程式的朋友來說「家目錄」可能就覺得有點陌生了,不過不要緊家目錄的觀念很簡單,它可以解釋成每一位登入電腦的使用者所私人擁有的資料夾。在Tcl裡家目錄的位置可以由全域變數$::env(HOME)來取得,::env陣列會在啟動Tcl程式時自動被建立,它裡面儲存了一些系統資訊,例如:環境變數、作業系統的版本、登入系統的帳號....等。有興趣的朋友可以去看看的Tcl文件,裡面有更詳細的說明,目前我們只要知道$::env(HOME)裡面儲存了家目錄的位置就可以了。下面是一個簡單的例子,它會印出家目錄的位置。
puts $::env(HOME) |
正常的情況下,在Linux的平台你應該會看到「/home/你登入的帳號」像這樣子的輸出。在Mac的平台會輸出「/Users/你登入的帳號」。在Windows下則會輸出「C:/Documents and Settings/你登入的帳號」。 配合上面的觀念,接下來我們就規劃把播放清單儲存在家目錄下的playlist.txt檔案裡好了。
26.2 自動儲存播放清單
要完成這項功能我們要寫一個新的程序叫做pl_save,這個程序要做的功能很簡單,就是把目前播放清單中的項目逐一取出,然後儲存在指定的檔案裡。它實際的程式碼如下:# 儲存播放清單的程序 proc pl_save {} { variable Priv variable pathTbl # 組合儲存播放清單的檔案路徑 set fpath [file join $::env(HOME) playlist.txt] # 取出播放清單中所有的項目 set allItems [$Priv(pl) children {}] # 開啟儲存播放清單的檔案 set fd [open $fpath w] # 把播放清單中的項目逐一存入檔案 foreach item $allItems { puts $fd $pathTbl($item) } # 關閉檔案 close $fd } |
在這個程序裡,我們把播放清單裡的每一個MP3都以一行一個項目的方式儲存在playlist.txt裡面。pl_save完成後,我們還要在每次MP3加入播放清單時執行它一次,也就是說我們要修改pl_add程序,修改的方法是在pl_add的尾巴加上一行pl_save。
# 把MP3加入清單方塊 proc pl_add {} { variable Priv variable pathTbl # 跳出選擇資料夾的對話方塊 set dir [tk_chooseDirectory -title "加入MP3"] # 判斷是否有選擇資料夾 if {[file exists $dir]} { # 掃描選中資料夾裡的MP3 foreach mp3 [glob -nocomplain -directory $dir -types {f} *.mp3] { # 把掃中的MP3加入清單方塊 set item [$Priv(pl) insert {} end -text [file rootname [file tail $mp3]]] # 記下item與完整路徑的關係 set pathTbl($item) $mp3 } } #=================注意這邊!! # 儲存播放清單 pl_save #================= } |
Ok!!自動儲存的功能完成了,現在你可以試試看把一些MP3加入播放清單然後關掉iPlayer,再去家目錄下找看看應該會有playlist.txt這個檔案,裡面會有我們儲存的內容。
26.3 自動載入播放清單
剛剛我們寫的pl_save程序可以把播放清單裡的MP3逐一儲存到檔案裡。接下來要實作的pl_load程序剛好是反其道而行,這次我們要把剛剛儲存的檔案內容,以一次一行的方法讀回播放清單,它的程式碼如下:#自動載入播放清單 proc pl_load {} { variable Priv variable pathTbl # 組合儲存播放清單的檔案路徑 set fpath [file join $::env(HOME) playlist.txt] # 如果儲存播放清單的檔案不存在就離開程序 if {![file exists $fpath]} {return 0} # 開啟儲存播放清單的檔案 set fd [open $fpath r] # 一次讀取一行,直到檔案讀取完畢 while {![eof $fd]} { # 讀一行到mp3變數 gets $fd mp3 # 如果mp3變數儲存的檔案不存在,就執行下一圈 if {![file exists $mp3]} {continue} # 把MP3加入清單方塊 set item [$Priv(pl) insert {} end -text [file rootname [file tail $mp3]]] # 記下item與完整路徑的關係 set pathTbl($item) $mp3 } # 關閉檔案 close $fd } |
為了讓這個程序可以正常的運作,我們還要在iPlayer啟動時執行一次這個程序,方法是在init程序執行它:
# init 程序用來處理所有程式初始化的工作 proc init {} { variable snd variable currentFile variable Priv # 載入snack 套件 package require snack # 建立播放物件 set snd [::snack::sound] # 執行圖形介面初始化 gui_init #======================注意這邊!! # 載入之前儲存的播放清單 pl_load #====================== #這個變數用來記錄播放狀態 set Priv(State) "STOP" # 把清單方塊綁定一個「滑鼠點兩下的事件」,當事件發生時就執行play程序 bind $Priv(pl) <Double-Button-1> {::iPlayer::play} } |
大功告成!! 現在iPlayer會自動載入播放清單內容了,請大家自己試試吧!!
26.5 結論
我們好不容易完成了一個MP3播放程式,雖然它的功能不是很完善,也還有很多可以改進的地方,不過以訓練寫程式來說,這次的iPlayer實作,應該是有達到某種程度的效果了。另外,老實說iPlayer的外觀真的是醜了點,不過我想改改外觀對你來說並不會是太大的困難才對,有興趣的朋友可以試著對iPlayer修修改改,把它改成更符合你個人使用的程式。希望大家玩的愉快~按右上方的「#」號切換側邊欄