使用shell指令碼建立好的圖形應用程式

來源:互聯網
上載者:User

這是今天csdn的諮詢報道,我覺得非常實用,而且之前沒有關注過shell還有圖形的潛質,所以特此作個筆記。

http://sd.csdn.net/a/20110420/296194.html ,作者:Martin Streicher

 

 

對話UNIX:使用shell指令碼建立好的圖形應用程式

 

簡介: 命令列不適合於每一位使用者。事實上,一些使用者可能僅在握著滑鼠時才感到舒服。要僅使用 shell 來滿足這些使用者或構建傳統型應用程式,可以向您的指令碼添加一些 GUI。這裡是一些具體做法。

如果您走進一個擁擠的機房,可能會聽到有關 “shebangs”、斜線、點、根、管道、連接埠等等這個那個的閑聊。如果講到 UNIX,您無疑會理解本地術語 — 有關 UNIX 的縮減詞、命令名、快速鍵、選項、檔案名稱和方言 — 且有賓至如歸的感覺。與其他藝術工作者一樣,UINX 使用者擁有廣泛的術語來描述其工作細節。

並非每個人都探討 UNIX;事實上,有些人可能發現命令列很複雜,令人卻步。此外,您可能不希望將全部命令列寄託給臨時或無經驗的使用者。要協助那些不習慣使用命令列的人,或構建圍繞 shell 的自訂解決方案,您可以為您的指令碼構建 GUI。有了這樣的工具 — dialog 和 Zenity 是兩個值得一提的工具(參見 參考資料) — 您就可以使用對話方塊、檔案瀏覽器和其他常見的 “windowing” 控制項和技術來與您的使用者互動。事實上,對話方塊提供更多自然對話:您提出問題,請求響應,並相應地予以響應。

本期的 “對話 UNIX” 探討 dialog 和 Zenity,並展示如何將任何指令碼轉化成一個令人信服的 GUI 應用程式。對於傳統的、基於文本的介面使用 dialog,Zenity 提供現代風格的視窗化案頭。

向任何 shell 指令碼添加對話方塊

一個命令列公用程式通常提供足夠的選項來完全控制每個調用。一些 DOS 命令可能啟用或禁用一個特性,而其他 DOS 命令可能處理參數,比如名稱列表。在命令列,您將(幾乎)所有資訊呈現在前面,然後執行任務。圖形應用程式很不同。選擇是通過菜單、複選框和檔案瀏覽器做出的。一個圖形應用程式接受一點資訊,處理它,然後通常要求獲得更多資訊。據說 GUI 應用程式是事件驅動的。

dialog 公用程式跨越兩個世界。當您需要來自使用者的輸入時調用該公用程式,然後返回到您的指令碼繼續處理提供的任何資料。換言之,如果您寫一個指令碼來使用 dialog,就有可能忽略命令列參數,而是使用 dialog 在必要時發出提示資訊。

如果您的系統缺少 dialog 公用程式,您可以便於使用目前的版本內建的包管理器來安裝它,或者您可以直接通過原始碼編譯它。例如,如果您的系統使用 Aptitude,您可以通過如下命令安裝 dialog:

 
  1. sudo apt-get install dialog 

否則就要通過原始碼編譯,可以下載維護人員 Thomas Dickey 的 Web 網站上的代碼(參見 參考資料)並運行典型的三個命令:./configure && make && make install:

 
  1. $ wget http://invisible-island.net/datafiles/release/dialog.tar.gz 
  2. $ tar xzf dialog.tar.gz 
  3. $ cd dialog-1.1-20100428 
  4. $ ./configure 
  5. $ make 
  6. $ sudo make install 

安裝完成之後,您的路徑中應當會有一個名為 dialog 的新公用程式。輸入 man dialog 來查看捆綁文檔。

dialog 使用起來很簡單:它僅是另一個 UNIX 命令。您使用命令選項顯示您選擇的對話方塊,然後捕獲結果並基於該值執行一些邏輯。dialog 的一些變體直接將命令結果放在特殊的 shell 狀態變數 $? 中,您應當在 dialog 命令退出後立即儲存或詢問該變數(因為隨後的一個命令會立即改變其值)。另外,通常更為複雜的 dialog 命令變體同時設定 shell 狀態變數並產生其他結果。為將事情簡單化,dialog 提供 --stdout 選項來將其結果發出到標準輸出,因而便於通過命令求值捕獲資料(帶左引號的命令和指派陳述式的組合)。

例如,dialog --yesno 命令是最簡單的變體之一。它提出一個問題,提示做出是或否的響應,並返回 $? 中的 0 或 1,具體取決於使用者選擇了 “Yes” 還是 “No”。您可以測試 $? 的值並執行一些條件代碼。這裡是您可以添加到 shell 指令碼的一個工作程式碼片段:

 
  1. dialog --yesno "Do you want to continue?" 0 0 
  2. rc=$? 
  3. if [ "${rc}" == "0" ]; then 
  4.   echo Yes 
  5. else 
  6.   echo No 
  7. fi 

--yesno 選項需要至少三個參數:問題文本以及對話方塊本身的高度和寬度,後者用行和列度量。如果您不需要特定尺寸,總是可以為高度或寬度使用 0,以自動調整對話方塊大小。(還有相對於視窗左下角放置視窗的選項。)圖 1 展示運行中的 --yesno。

圖 1. --yesno 操作

dialog 選項 --calendar 呈現一個日曆來允許使用者選擇特定日期。如果使用者選擇一個日期,然後單擊 OK,命令返回 0。但是,如果使用者單擊 Cancel,命令返回 1。此外,如果使用者單擊 OK,命令將選定日期發出為標準輸出。這裡是使用命令求值產生日期的一個例子:

 
  1. RESULT=`dialog --stdout --title "CALENDAR"  
  2.     --calendar "Please choose a date..." 0 0 9 1 2010` 
  3. retval=$? 

--title 選項使用下一個參數來將一個標題添加到對話方塊,且可用於任何 dialog 命令。非常像 --yesno,您提供一些文本來提示使用者。接下來,選項 0 0 再次指定自動高度和寬度,選項 9 1 2010 分別指示日曆中顯示的初始日、月和年。選項卡和方向鍵改變日曆並選擇一個日期。對話方塊退出後,如果 retval 是 0,RESULT 的值就是選定的日期。圖 2 顯示日曆對話方塊。

圖 2. 日曆對話方塊

dialog 命令提供通常在圖形應用程式中找到的大部分控制項:

--infobox 僅僅展示資訊:它不要求任何輸入。資訊框仍然只是簡單地在螢幕上。要延長其顯示,在它和下一個命令之前置入一個 sleep 命令。

--input 收集單一輸入響應。您可能會使用該命令來收集您的使用者的姓名或郵遞區號。

--textbox 顯示一個文字檔的內容。如果檔案超出對話方塊的垂直高度,一個控制項支援簡單的向上和向下滾動。

--menu 和 --radiolist 提供一個挑選清單,供使用者進行選擇。兩種對話方塊在功能上是等同的,但是略有不同的視覺風格,以更好地類比一個 GUI 可能展示的東西。特別地,--radiolist 命令呈現 ( ) 來類比選項按鈕。

--checklist 顯示使用者可單獨啟用或禁用的一個項目列表。

每個 dialog 變體的輸出不同,或是一個單一值,或是一列由空格分隔的帶引號值。例如,--checklist 是用於選擇一個或多個選項的一個不錯的控制項,它發出一列帶引號值,其中每個值與一個啟用的選項相關。下面示範了一個操作樣本:

 
  1. RESULT=`dialog --stdout  
  2.    --checklist "Enable the account options you want:" 10 40 3 / 
  3.   1 "Home directory" on / 
  4.   2 "Signature file" off / 
  5.   3 "Simple password" off` 

行 1、2 和 3 結尾的反斜線(/)是延續標記;從 RESULT 到 off` 的一切內容是一個命令。如果使用者啟用了 Home directory 和 Simple password,$RESULT 將會是 "1" "3"。--checklist 的參數是高度和寬度,任何時間內的列表元數量(如果有些項目被擋住,您可以通過滾動查看這些項目),以及清單選項(其中每個選項是一個值)、一個描述、在最初啟用或禁用該選項。

您可以隨時輸入 dialog --help 來查看常規列表,輸入 dialog 來查看特定選項。dialog 有無數用法。

有像素?使用 Zenity。

Zenity 是 UNIX 案頭,如同 dialog 是簡單的終端視窗。您可以使用 Zenity 從任何 shell 指令碼開啟 GTK+ 對話方塊。事實上,Zenity 與 dialog 有著許多相同的功能;惟一的區別在於,Zenity 在一個 X Window System 環境中工作。Zenity 與 GNOME 相捆綁。如果您不運行 GNOME,可以單獨安裝 Zenity(但是,也要安裝大量 GTK+ 庫)。您還可以從 GNOME 項目頁面下載 Zenity 的原始碼(參見 參考資料 擷取連結)。

下面是一個簡單的例子。命令為:

 
  1. zenity --question --text "Do you want to continue?" 

產生的結果如 圖 3 所示。(用於示範的機器在運行 Ubuntu 10。)如果您單擊 OK,命令返回 0。否則,它返回 1。

圖 3. 一個簡單問題

如同 dialog,Zenity 有很多選項 — 甚至比 dialog 還多 — 但是選項命名貼切,因而不言自明。您可能發現 Zenity 比 dialog 更有優勢,特別是由於大部分電腦使用者都有某種 X 案頭。

Zenity 提供與 dialog 相同的許多控制項。這裡是收集名稱的一個程式碼片段:

 
  1. ENTRY=`zenity --entry --text "Please enter your name"  
  2.    --entry-text "Your name" --title "Enter your name" 
  3. if [ $? == 0 ]; then 
  4.   zenity --info --text "Hello $ENTRY/!" 
  5. fi 

再次說明,如果 zenity 的結束代碼是 0,那麼 ENTRY 有某人的姓名。這裡是為使用 Zenity 而重寫後的日曆樣本:

 
  1. DATE=`zenity --calendar --day "9" --month "1" --year "2010" --format "%Y-%m-%d" 
  2. if [ $? == 0 ]; then 
  3.   echo $DATE 
  4. fi 

儘管 Zenity 更詳細一點 — 例如,對於年、月、日有單獨的選項 — 其他 DOS 命令使您免於記住精確的參數使用順序。Zenity 的日曆還允許您指定輸出格式,即使用標準 strftime() 代碼。該命令的結果類似於 2010-1-9,它表示 2010 年 1 月 9 日。

Zenity 還提供一個過程表來展示一個操作的狀態。它從標準輸入逐行讀取資料。如果一個行的首碼是井號(#),文本被更新為該行文本。如果一個行僅包含一個數字,百分比被更新為該數字。清單 1 展示 Zenity 文檔中的一個樣本。

清單 1. Zenity 過程表

 
  1. #!/bin/sh 
  2.   echo "10" ; sleep 1 
  3.   echo "# Updating mail logs" ; sleep 1 
  4.   echo "20" ; sleep 1 
  5.   echo "# Resetting cron jobs" ; sleep 1 
  6.   echo "50" ; sleep 1 
  7.   echo "This line will just be ignored" ; sleep 1 
  8.   echo "75" ; sleep 1 
  9.   echo "# Rebooting system" ; sleep 1 
  10.   echo "100" ; sleep 1 
  11. ) | 
  12. zenity --progress / 
  13.   --title="Update System Logs" / 
  14.   --text="Scanning mail logs..." / 
  15.   --percentage=0 
  16.  
  17. if [ "$?" = -1 ] ; then 
  18.   zenity --error / 
  19.     --text="Update canceled." 
  20. fi 

sub-shell(包含在括弧中)執行一系列任務 — 在這個人為例子中 albeit sleep 延遲 — 且通過一個管道將輸出發出到一個 Zenity 過程表。在每一步之前,sub-shell 發出一個數字來推進過程表,每個 --percentage 0 起始於 0,然後發出一個以 # 開頭的字串來改變狀態訊息。因此,過程表沿著步驟標記指令碼工作。如果 Zenity 的結束代碼是 -1,單擊的是 Cancel 按鈕。

再次說明,要使用 dialog 或 Zenity,用對話方塊替換您之前引用過命令列參數的代碼。用一個小創意,您可以將您的 shell 指令碼轉化為一等案頭公民。

其他進階工具

有些時候,您可能發現您的需求超過了 shell 指令碼以及 dialog 和 Zenity 工具的功能範圍之外。在那些執行個體中,您可能轉向 C/C++ 並為案頭構建本機應用程式,但是您還可以使用進階指令碼語言和許多強大的 G使用者介面架構的語言綁定。

一個組合是 Ruby 指令碼語言和 wxWidgets 架構的 Ruby 綁定。Ruby 是物件導向的、富於表現力的且簡潔的,運行於大部分作業系統之上。wxWidgets 架構還可用於每個主流平台,包括 Mac OS X、Windows、Linux 和 UNIX。由於兩者都是可移植的,您可以用 Ruby 編寫一個應用程式一次,然後隨處運行它。另一個更簡單的選擇是 Shoes。儘管不如 wxWidgets 豐富,Shoes 學習和使用起來相當簡單。清單 2 使用 70 行代碼實現了一個計算機。

清單 2. 用 Shoes 實現的一個計算機

 
  1. class Calc 
  2.   def initialize 
  3.     @number = 0 
  4.     @previous = nil 
  5.     @op = nil 
  6.   end 
  7.  
  8.   def to_s 
  9.     @number.to_s 
  10.   end 
  11.  
  12.   (0..9).each do |n| 
  13.     define_method "press_#{n}" do 
  14.       @number = @number.to_i * 10 + n 
  15.     end 
  16.   end 
  17.  
  18.   def press_clear 
  19.     @number = 0 
  20.   end 
  21.  
  22.   {'add' => '+', 'sub' => '-', 'times' => '*', 'div' => '/'}.each do |meth, op| 
  23.     define_method "press_#{meth}" do 
  24.       if @op 
  25.         press_equals 
  26.       end 
  27.       @op = op 
  28.       @previous, @number = @number, nil 
  29.     end 
  30.   end 
  31.  
  32.   def press_equals 
  33.     @number = @previous.send(@op, @number.to_i) 
  34.     @op = nil 
  35.   end 
  36. end 
  37.  
  38. number_field = nil 
  39. number = Calc.new 
  40. Shoes.app :height => 250, :width => 200, :resizable => false do 
  41.   background "#EEC".."#996", :curve => 5, :margin => 2 
  42.  
  43.   stack :margin => 2 do 
  44.  
  45.     stack :margin => 8 do 
  46.       number_field = para strong(number) 
  47.     end 
  48.  
  49.     flow :width => 218, :margin => 4 do 
  50.       %w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn| 
  51.         button btn, :width => 46, :height => 46 do 
  52.           method = case btn 
  53.             when /[0-9]/; 'press_'+btn 
  54.             when 'Clr'; 'press_clear' 
  55.             when '='; 'press_equals' 
  56.             when '+'; 'press_add' 
  57.             when '-'; 'press_sub' 
  58.             when '*'; 'press_times' 
  59.             when '/'; 'press_div' 
  60.           end 
  61.  
  62.           number.send(method) 
  63.           number_field.replace strong(number) 
  64.         end 
  65.       end 
  66.     end 
  67.   end 
  68. end 

對 Ruby 和 Shoes 的介紹不在本文討論範圍之內,但是這裡是一些最重要的構造:

大多數 Ruby 類 Calc 使用 Ruby 的元編程功能,在運行時為所有數字鍵和數學操作鍵定義功能。

代碼開頭 Shoes.app... 建立計算機的 GUI,為其呈現布局和按鈕。Shoes 提供兩個容器來裝配布局:stack 和 flow。一個 stack 是元素的一個垂直堆棧,其中每個元素直接放在前一個元素下面。一個 flow 盡量緊密地包裹元素,直至它達到其邊框局限,然後封裝其餘的元素。(您可以將一個堆棧看作是一個 HTML <div>,將一個流看作 HTML <p>。)您可以使用 Ruby 塊建立一個堆棧或一個流。

最裡面的 flow 快迴圈建立應用程式中的所有按鈕,並有效地將每個按鈕綁定到其方法。(case 語句返回一個方法名稱;number.send(method) 行調用執行個體化計算機上的那個方法。)

number_field.replace strong(number) 行通過最新計算結果更新計算機顯示。發出 number 致使類調用其自己的 to_s (“to string”) 方法。

其他指令碼語言擁有類似的庫,且 Ruby 本身有更多選擇,包括 Ruby Cocoa,可使用 Ruby 在 Mac OS X 上開發 Cocoa 應用程式。選擇您喜歡的開源指令碼語言,找到一個輕量級 GUI 工具包,然後開始編碼。

您不需要討厭的編譯器!

如果您已經掌握了 shell 指令碼編寫,將您的工作與 dialog 或 Zenity 結合起來,以增加互通性。如果您需要的編程功能比 shell 提供的更多,考慮 Ruby 或 Python 這樣的語言以及任何視窗工具包。您無需一個編譯器來編寫良好的傳統型應用程式。

關於作者

Martin Streicher 是一位 Ruby on Rails 的自由開發人員和 Linux Magazine 的前任主編。Martin 畢業於 Purdue University 並獲得電腦科學學位,從 1986 年起他一直從事 UNIX 類系統的編程工作。他喜歡收集藝術品和玩具。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.