国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

directory search
Ruby用戶指南 3、開始 4、簡單的例子 5、字符串 6、正則表達式 7、數(shù)組 8、回到那些簡單的例子 9、流程控制 10、迭代器 11、面向?qū)ο笏季S 12、方法 13、類 14、繼承 15、重載方法 16、訪問控制 17、單態(tài)方法 18、模塊 19、過程對象 20、變量 21、全局變量 22、實變量 23、局部變量 24、類常量 25、異常處理:rescue 26、異常處理:ensure 27、存取器 28、對象的初始化 29、雜項 RGSS入門教程 1、什么是RGSS 2、開始:最簡單的腳本 3、數(shù)據(jù)類型:數(shù)字 4、數(shù)據(jù)類型:常量與變量 5、數(shù)據(jù)類型:字符串 6、控制語句:條件分歧語句 7、控制語句:循環(huán) 8、函數(shù) 9、對象與類 10、顯示圖片 11、數(shù)組 12、哈希表(關(guān)聯(lián)數(shù)組) 13、類 14、數(shù)據(jù)庫 15、游戲?qū)ο?/a> 16、精靈的管理 17、窗口的管理 18、活動指令 19、場景類 Programming Ruby的翻譯 Programming Ruby: The Pragmatic Programmer's Guide 前言 Roadmap Ruby.new 類,對象和變量 容器Containers,塊Blocks和迭代Iterators 標準類型 深入方法 表達式Expressions 異常,捕捉和拋出(已經(jīng)開始,by jellen) 模塊 基本輸入輸出 線程和進程 當遭遇挫折 Ruby和它的世界 Ruby和Web開發(fā) Ruby Tk Ruby 和微軟的 Windows 擴展Ruby Ruby語言 (by jellen) 類和對象 (by jellen) Ruby安全 反射Reflection 內(nèi)建類和方法 標準庫 OO設(shè)計 網(wǎng)絡(luò)和Web庫 Windows支持 內(nèi)嵌文檔 交互式Ruby Shell 支持 Ruby參考手冊 Ruby首頁 卷首語 Ruby的啟動 環(huán)境變量 對象 執(zhí)行 結(jié)束時的相關(guān)處理 線程 安全模型 正則表達式 字句構(gòu)造 程序 變量和常數(shù) 字面值 操作符表達式 控制結(jié)構(gòu) 方法調(diào)用 類/方法的定義 內(nèi)部函數(shù) 內(nèi)部變量 內(nèi)部常數(shù) 內(nèi)部類/模塊/異常類 附加庫 Ruby變更記錄 ruby 1.6 特性 ruby 1.7 特性 Ruby術(shù)語集 Ruby的運行平臺 pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
characters

Ruby和 Tk


譯者注:因原來的發(fā)布不帶圖片,所以本章圖片選自
http://www.ruby.no/prosjekt/ProgrammeringIRuby/ext_tk.html,不是英語,可能看不清,不過界面都顯示出來了。

Ruby Application Archive (簡稱RAA)包括幾個支持你使用Ruby來創(chuàng)建GUI(Graphical User Interface)程序的擴展(extensions ),包括Tcl/Tk擴展,GTK擴展,OpenGL擴展和其它的一些。

 

TK擴展是隨著Ruby軟件一起發(fā)布的,可以在Unix和windows上使用。為了使用它,你需要在你的系統(tǒng)上安裝Tk。Tk是一個龐大的系統(tǒng),關(guān)于它的書已經(jīng)有很多了,所以我們不會在這里浪費太多的時間和資源去深入的研究Tk本身,而是著重于如何在Ruby中使用Tk。要想很好的在Ruby中使用Tk,你需要下面的一些參考書中的一本。因為Tk和Ruby的綁定和Tk到Perl的綁定類似,所以你可以用Learning Perl/Tk? 或者 Perl/Tk Pocket Reference

Tk以一種組合的方式工作,就是說你首先創(chuàng)建一個容器(container )部件(widget ),比如TkFrame 或者TkRoot,然后在它上面繼續(xù)創(chuàng)建其它部件,比如按鈕或者標簽(labels)。當你打算開始啟動GUI的時候,調(diào)用Tk.mainloop,然后Tk引擎將接替對程序的控制,顯示各個窗口部件,響應(yīng)各種GUI事件。

 

簡單的Tk應(yīng)用程序

Ruby中一個簡單的Tk應(yīng)用程序像下面一樣:

 

require?'tk'
root?=?TkRoot.new?{?title?"Ex1"?}
TkLabel.new(root)?{
??text??'Hello,?World!'
??pack??{?padx?15?;?pady?15;?side?'left'?}
}
Tk.mainloop

界面如圖:

讓我們更近距離的看看這些代碼。在裝載完tk擴展模塊之后,我們用TkRoot.new建立了一個最頂級(root-level )的框架(frame)。然后,我們建立了一個標簽部件作為這個父級窗口的子部件,并設(shè)置了這個標簽的一些屬性,最后,最后,我們讓父窗口顯示(pack?)并進入GUI主事件循環(huán)。

顯示的建立一個頂級窗口是一個很好的習慣,盡管你不建立這個窗口程序也能工作。例如上面的代碼即使變?yōu)橐韵氯幸材芄ぷ鳎?/p>

 

require?'tk'
TkLabel.new?{?text?'Hello,?World!'?}
Tk.mainloop

這樣就可以工作了,再參考一下上面我們提到的Perl/Tk的書,我們就能寫出非常好的GUI程序了。但是,下面我們還是會更詳細的講述一下Tk在Ruby中的使用。

窗口部件(Widgets)

創(chuàng)建一個窗口部件很容易,在Ruby中這些部件名字都在原來的基礎(chǔ)上加上了Tk前綴,比如,Label,Button和Entry變成了TkLabel,TkButtonTkEntry。你可以通過使用new方法創(chuàng)建一個部件,就像創(chuàng)建其它對象一樣。如果你創(chuàng)建組件的時候沒有指定父部件的名字,那么將把頂級窗口作為默認父部件。我們有時候也會在創(chuàng)建部件的時候設(shè)置一些部件屬性(選項),比如顏色,大小等等;有時候,我們也希望從這些部件得到程序返回信息,我們可以設(shè)置回調(diào)(callbacks )方法和共享數(shù)據(jù)(sharing data)。

設(shè)置部件(Widget)選項

如果你看一下Tk的參考手冊(比如關(guān)于Perl/Tk),你會發(fā)現(xiàn)這些窗口部件選項可以用一個連字符列出(listed with a hyphen ),就像命令行參數(shù)那樣。在Perl/Tk中,你可以將這些參數(shù)放入一個Hash傳給這個widget,在Ruby中你也可以這么做,但是,你也可以通過一個代碼block來設(shè)置這些參數(shù):選項的名稱作為方法名,選項的值作為這個方法的參數(shù)。一個widget創(chuàng)建時候的第一個參數(shù)為父部件,然后后面跟一個哈希結(jié)構(gòu)的選項列表,或者以代碼塊格式來設(shè)置這些選項。所以,下面這兩項實際上是相等地。

TkLabel.new(parent_widget)?{
??text????'Hello,?World!'
??pack('padx'??=>?5,
???????'pady'??=>?5,
???????'side'??=>?'left')
}
#?or
TkLabel.new(parent_widget,?text?=>?'Hello,?World!').pack(...)

不過有一個需要注意的小地方:有時候變量的作用域可能出乎你的想象。block是在widget的環(huán)境上下文中執(zhí)行(evaluated ),而不是調(diào)用者的(caller's)。這就意味著調(diào)用者的實例變量在這個block中不可用,但是在包含它的范圍內(nèi)的局部變量和全局變量(不是你曾經(jīng)用過的)。我們將在后面的例子中使用這兩種方法設(shè)置widget的選項。

不確定的英文原文:The block is actually in the context of the widget's object, not the . This means that the caller's instance variables will not be available in the block, but local variables from the enclosing scope and globals (not that you ever use those) will be.

距離(比如上面例子中的padx和pady)默認單位為象素,但是你也可以指定為其它單位,比如以c為后綴表示單位為厘米,i表示英寸,m表示毫米,p表示點(point)等。

 

取得Widget的數(shù)據(jù)

我們可以通過方法回調(diào)和綁定變量(binding variables)從窗口部件得到信息。

回調(diào)(Callbacks )很容易使用。command選項(比如下面例子中的TkButton)接收一個Proc對象,這個Proc對象會在這個回調(diào)觸發(fā)的時候被調(diào)用。這里,我們可以用 Kernel::proc 將block {exit}轉(zhuǎn)換為一個Proc對象。

TkButton.new(bottom)?{
??text?"Ok"
??command?proc?{?p?mycheck.value;?exit?}
??pack('side'=>'left',?'padx'=>10,?'pady'=>10)
}

我們也可以使用TkVariable 代理將Ruby的變量綁定到 Tk widget的值。注意下面的TkCheckButton 是如何創(chuàng)建的,variable選項接受一個TkVariable類型的參數(shù),這個例子里我們用 TkVariable.new首先創(chuàng)建了這個變量。訪問變量mycheck.value將根據(jù)這個選擇框是否被選中而返回0或1。你可以在各種支持variable選項的部件中使用這種方法,比如radio,button和文本框。

mycheck?=?TkVariable.new

 
TkCheckButton.new(top)?{    
??variable?mycheck    
??pack('padx'=>5,?'pady'=>5,?'side'?=>?'left')    
}
  

動態(tài)設(shè)置和獲取選項

除了在創(chuàng)建一個部件的時候設(shè)定選項,我們也可以在這個部件運行的時候重新配置它。每個widget都支持configure方法,這個方法接收一個Hash或者代碼塊作為參數(shù),和new方法類似,比如我們可以修改一下第一個例子,使它的按鈕在按下的時候能給修改標簽的文本。

lbl?=?TkLabel.new(top)?{?justify?'center'
??text????'Hello,?World!';
??pack('padx'=>5,?'pady'=>5,?'side'?=>?'top')?}
TkButton.new(top)?{
??text?"Cancel"
??command?proc?{?lbl.configure('text'=>"Goodbye,?Cruel?World!")?}
??pack('side'=>'right',?'padx'=>10,?'pady'=>10)
}

所以,當你按Cancel按鈕的時候,標簽的文本將由``Hello, World!'' 變?yōu)閌`Goodbye, Cruel World!''。

你也可以用cget方法取得某個widget的某個選項的值。

require?'tk'
b?=?TkButton.new?{
??text?????"OK"
??justify??'left'
??border???5
}
b.cget('text') ? "OK"
b.cget('justify') ? "left"
b.cget('border') ? 5

程序示例

下面來看一個稍微長點例子,一個真正的應(yīng)用程序-``pig Latin''生成器。輸入一個短語,比如 ``Ruby rules'' ,然后按下按鈕``Pig It'',程序?qū)⒘⒓窗堰@個短語翻譯為

require?'tk'

 
class?PigBox     
??def?pig(word)     
????leadingCap?=?word?=~?/^A-Z/     
????word.downcase!     
????res?=?case?word     
??????when?/^aeiouy/     
????????word+"way"     
??????when?/^([^aeiouy]+)(.*)/     
????????$2+$1+"ay"     
??????else     
????????word     
????end     
????leadingCap???res.capitalize?:?res     
??end
 
??def?showPig     
????@text.value?=?@text.value.split.collect{|w|?pig(w)}.join("?")     
??end
 
??def?initialize     
????ph?=?{?'padx'?=>?10,?'pady'?=>?10?}?????#?common?options     
????p?=?proc?{showPig}
 
????@text?=?TkVariable.new     
????root?=?TkRoot.new?{?title?"Pig"?}     
????top?=?TkFrame.new(root)     
????TkLabel.new(top)?{text????'Enter?Text:'?;?pack(ph)?}     
????@entry?=?TkEntry.new(top,?'textvariable'?=>?@text)     
????@entry.pack(ph)     
????TkButton.new(top)?{text?'Pig?It';?command?p;?pack?ph}     
????TkButton.new(top)?{text?'Exit';?command?{proc?exit};?pack?ph}     
????top.pack('fill'=>'both',?'side'?=>'top')     
??end     
end
 
PigBox.new     
Tk.mainloop
   

界面如圖:

 

Sidebar: 布局管理器?(Geometry Management)

在本章的例子中,我們已經(jīng)看到了pack方法,這是一個非常重要的方法,如果你不調(diào)用這個方法,那么你的widget將永遠不會出現(xiàn),pack命令將告訴geometry manager將這個部件按照設(shè)定的參數(shù)放到合適的位置上。支持三種命令:

命令 定位標準
pack 靈活的,基于約束(constraint)的定位
place Absolute position
grid Tabular (row/column) position

因為pack可能是最常用的方法了,所以我們的例子里都使用pack方法。

譯者注:如果一個方法(method)沒有參數(shù),有時候也叫做命令(command)

綁定事件(Binding Events)

我們的窗口部件是暴露給現(xiàn)實世界的,人們可以在它上面點擊,移動鼠標,進入這個組件等。所有的這些事情,都會產(chǎn)生一個事件,我們也可以捕獲這些事件。你可以通過窗口部件的bind方法,給它的某一事件綁定一個事件處理,通常,這個時間處理是一個代碼塊(block of code)。

比如,我們創(chuàng)建了一個用來顯示一個圖像的按鈕,我們希望鼠標在這個按鈕上移動的時候圖像會變化,則可以用以下代碼:

 

image1?=?TkPhotoImage.new?{?file?"img1.gif"?}
image2?=?TkPhotoImage.new?{?file?"img2.gif"?}

 
b?=?TkButton.new(@root)?{      
??image????image1      
??command??proc?{?doit?}      
}
 
b.bind("Enter")?{?b.configure('image'=>image2)?}      
b.bind("Leave")?{?b.configure('image'=>image1)?}
   

首先,我們用TkPhotoImage創(chuàng)建了2個GIF圖像,然后,創(chuàng)建了一個按鈕,名字為b,它顯示的圖像為image1,然后我們將它的Enter方法綁定一個將它的圖像變?yōu)閕mage2的代碼塊,Leave事件幫定到恢復image1圖像的代碼塊。

這個例子顯示了簡單的Enter和Leave方法,而且,bind方法的參數(shù)可以有幾個子字符串構(gòu)成,每個串之間用減號分割,順序為modifier-modifier-type-detail。 修飾符(Modifiers )可以在Tk的參考手冊中找到,包括Button1, Control, Alt, Shift等等,type是事件的名字(遵循X11的命名習慣),包括ButtonPress,KeyPress和Expose等。Detail或者是一個用于表示button的從1到5的數(shù)字,或者用來表示鍵盤輸入的keysym。比如,如果我們想處理事件:在control鍵被按下的時候釋放鼠標的button1,可以如下表示:

Control-Button1-ButtonRelease
或者
Control-ButtonRelease-1

事件本身也會包含一些特定的字段(fields ),比如事件的發(fā)成的時間,坐標x,y的值等。bind可以將這些屬性傳給一個回調(diào)方法,這叫做event field codes 。這種方法使用起來類似printf的規(guī)則,比如,為了得到一個鼠標移動時候的xy坐標值,我們可以給bind方法傳3個參數(shù),第二個參數(shù)是一個用于回調(diào)的Proc對象,第三個參數(shù)是包括事件屬性的字符串(event field string)

canvas.bind("Motion",?proc{|x,?y|?do_motion?(x,?y)},?"%x?%y")

畫布Canvas

Tk提供了一個畫布(canvas)部件,你可以在上面進行繪畫,然后輸出為PostScript 格式。這里是一個簡單的例子,來自Ruby發(fā)布。按下鼠標按鍵1,然后拖動,當松開按鍵1的時候,將會在兩個點之間劃一條直線。按下按鍵2將會把這個畫布轉(zhuǎn)出為適合打印的PostScript 格式。

require?'tk'
class?Draw 
??def?do_press(x,?y) 
????@start_x?=?x 
????@start_y?=?y 
????@current_line?=?TkcLine.new(@canvas,?x,?y,?x,?y) 
??end 
??def?do_motion(x,?y) 
????if?@current_line 
??????@current_line.coords?@start_x,?@start_y,?x,?y 
????end 
??end 
??def?do_release(x,?y) 
????if?@current_line 
??????@current_line.coords?@start_x,?@start_y,?x,?y 
??????@current_line.fill?'black' 
??????@current_line?=?nil 
????end 
??end 
??def?initialize(parent) 
????@canvas?=?TkCanvas.new(parent) 
????@canvas.pack 
????@start_x?=?@start_y?=?0 
????@canvas.bind("1",?proc{|e|?do_press(e.x,?e.y)}) 
????@canvas.bind("2",?proc{?puts?@canvas.postscript({})?}) 
????@canvas.bind("B1-Motion",?proc{|x,?y|?do_motion(x,?y)},?"%x?%y") 
????@canvas.bind("ButtonRelease-1", 
?????????????????proc{|x,?y|?do_release?(x,?y)},?"%x?%y") 
??end 
end
 
root?=?TkRoot.new{?title?'Canvas'?} 
Draw.new(root) 
Tk.mainloop
 

只需要用鼠標點幾下,就能創(chuàng)作出你的杰作了。

界面如下:

 

滾動Scrolling

除非你只想畫一個非常小的圖畫,否則上面的程序肯定不會很適合的。TkCanvas, TkListboxTkText 都可以支持滾動條,所以你能處理一個“大圖象”的一部分

滾動條和widget之間的通信是雙向的,移動滾動條的話widget的視圖也會移動,而widget的試圖被其他方法移動之后,滾動條也必須相應(yīng)的變化。

我們以前還沒有怎么介紹列表框(listbox),我們下面的滾動條的例子將使用一個列表框。下面的例子中,我們先創(chuàng)建一個普通的TkListbox,然后,又創(chuàng)建一個TkScrollbar,通過command選項為這個滾動條增加了一個回調(diào),這個回調(diào)將調(diào)用列表的yview方法,這個方法用來在縱坐標方向改變list的可見部分。

在回調(diào)建立之后,我們反過來也需要在list在移動之后,滾動條的設(shè)置也要改變,可以用TkScrollbar#set方法。下面的例子只是下一節(jié)例子中的一部分代碼。

 

list_w?=?TkListbox.new(frame,?'selectmode'?=>?'single')

 
scroll_bar?=?TkScrollbar.new(frame,  
??????????????????'command'?=>?proc?{?|*args|?list_w.yview?*args?})
 
scroll_bar.pack('side'?=>?'left',?'fill'?=>?'y')
 
list_w.yscrollcommand(proc?{?|first,last|  
?????????????????????????????scroll_bar.set(first,last)?})
 

 

Just One More Thing

我們可以用幾百頁來繼續(xù)討論Tk,但是那是其它的書本的內(nèi)容了。下面的程序是我們最后的Tk例子,一個簡單的GIF圖像查看器。你可以從一個列表框選擇一個GIF文件名,然后顯示一個適應(yīng)窗口大小的圖像。這里有一些內(nèi)容需要指出。

你是否看見過一個應(yīng)用程序?qū)⒐鈽嗽O(shè)置為忙狀態(tài)(沙漏)而忘了改回來嗎?在Ruby中則不必擔心這種情況的發(fā)生。還記得 File.new 方法能接收一個block而確保文件最后被關(guān)閉嗎,我們可以同樣的在busy方法中使用這種機制,來確保最后光標被恢復,如下面的例子。

這個例子也顯示了TkListbox 的一些其它常用方法,向它增加元素,建立鼠標鍵松開時候的事件回調(diào)[你也許需要鼠標松開事件,而不是按下事件,鼠標按下的時候表示選擇了一個widget],并且得到選擇的那一個元素等。

到目前位置我們用TkPhotoImage 直接來顯示圖片,我們也可以對它進行縮放,抽樣(subsample),或者只顯示它的一部分。這里,我們用到了subsample 來使圖片適合預覽。

require?'tk'

 
def?busy   
??begin   
????$root.cursor?"watch"?#?Set?a?watch?cursor   
????$root.update?#?Make?sure?it?updates??the?screen   
????yield?#?Call?the?associated?block   
??ensure   
????$root.cursor?""?#?Back?to?original   
????$root.update   
??end   
end
 
$root?=?TkRoot.new?{title?'Scroll?List'}   
frame?=?TkFrame.new($root)
 
list_w?=?TkListbox.new(frame,?'selectmode'?=>?'single')
 
scroll_bar?=?TkScrollbar.new(frame,   
??????????????????'command'?=>?proc?{?|*args|?list_w.yview?*args?})
 
scroll_bar.pack('side'?=>?'left',?'fill'?=>?'y')
 
list_w.yscrollcommand(proc?{?|first,last|   
?????????????????????????????scroll_bar.set(first,last)?})   
list_w.pack('side'=>'left')
 
image_w?=?TkPhotoImage.new   
TkLabel.new(frame,?'image'?=>?image_w).pack('side'=>'left')   
frame.pack
 
list_contents?=?Dir["screenshots/gifs/*.gif"]   
list_contents.each?{|x|   
??list_w.insert('end',x)?#?Insert?each?file?name?into?the?list   
}   
list_w.bind("ButtonRelease-1")?{   
??index?=?list_w.curselection[0]   
??busy?{   
????tmp_img?=?TkPhotoImage.new('file'=>?list_contents[index])   
????scale???=?tmp_img.height?/?100   
????scale???=?1?if?scale?<?1   
????image_w.copy(tmp_img,?'subsample'?=>?[scale,scale])   
????tmp_img?=?nil?#?Be?sure?to?remove?it,?the   
????GC.start??????#?image?may?have?been?large   
??}   
}

Tk.mainloop

譯者注:上面代碼倒數(shù)第七行,即copy圖像的那一行,在我的系統(tǒng)(2000+ruby 1.8.2)上運行出錯,改為如下即可通過:image_w.copy(tmp_img, '-subsample 2 2')?

界面如下:

最后再來看看垃圾收集,當我們有一些很大的圖片時,我們不想讓這些圖片在不需要的時候占用內(nèi)存,所以我們把對這個對象的引用設(shè)為nil,這就告訴了垃圾收集器立即把這些變量清理。

 

借鑒Perl/Tk文檔

就說道這里了,你已經(jīng)初步了解了在Ruby中使用Tk。在很大程度上,你可以輕松的在Ruby中借鑒適用于Perl/Tk的文檔,但是這里有一些要注意,不是每個在Perl中實現(xiàn)的方法在Ruby中也被實現(xiàn),而且也可能存在沒有被文檔化的功能。在關(guān)于Ruby/Tk的書出來之前,你最好還是有什么問題到新聞組上去討論,或者閱讀更多的源代碼。

但是通常來說,你會直到如何去做。記住部件的選項可以通過一個哈?;蛘叽ablock傳給widget,而且TkWidget 中代碼塊方法的變量作用域在這個widget內(nèi),而不是在類的實例中。

Object 的創(chuàng)建

Perl/Tk:??$widget?=?$parent->Widget(?[?option?=>?value?]?)
Ruby:?????widget?=?TkWidget.new(parent,?option-hash)
??????????widget?=?TkWidget.new(parent)?{?code?block?}

你也許不需要保存新創(chuàng)建widget的返回值,盡管這個值可以得到。不要忘了調(diào)用一個widget 的pack方法,否則你將不會看到這個部件。

選項(Options)

Perl/Tk:??-background?=>?color
Ruby:?????'background'?=>?color
??????????{?background?color?}

記住代碼塊的作用域是不同的。

變量引用(Variable References)

Perl/Tk:??-textvariable?=>?\$variable
??????????-textvariable?=>?varRef
Ruby:?????ref?=?TkVariable.new
??????????'textvariable'?=>?ref
??????????{?textvariable?ref?}

使用將一個Ruby變量綁定到widget的值,然后,你就可以用TkVariable 里的value的訪問方法(TkVariable#valueTkVariable#value=)來直接處理widget的內(nèi)容了。


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright ? 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).

Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.

Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
Previous article: Next article: