#

這一個章節將完成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修修改改,把它改成更符合你個人使用的程式。希望大家玩的愉快~

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