|
|||
Forrige < |
Innhold ^
|
Neste >
|
TkFrame
eller TkRoot
)
og deretter lager du de widgets som skal være inne i beholderen,
slik som knapper og tekst. Når du er klar for å starte det grafiske
brukergrensesnittet, kaller du Tk.mainloop
. Tk sin motor tar da
kontroll over programmet, viser widgets og kaller din kode når den mottar
hendelser i fra grensesnittet.
require 'tk' root = TkRoot.new { title "Ex1" } TkLabel.new(root) { text 'Hello, World!' pack { padx 15 ; pady 15; side 'left' } } Tk.mainloop |
Figur 15.1: Hello world program skjermbilde |
tk
utvidelsesmodulen, lager vi en
rotnivå vindusramme ved hjelp av TkRoot.new
.
Deretter lager vi en tekst widget som blir barnet til rotrammen.
Helt til slutt pakker vi rotrammen og går inn i grensesnittets hendelsesløkke.
Det er en god vane å angi rotrammen eksplisitt, men du kunne ha utelatt den---sammen med de ekstra opsjonene---og kuttet dette ned til en tre-linjers snutt:
require 'tk' TkLabel.new { text 'Hello, World!' } Tk.mainloop |
Tk
foran. For eksempel blir widgets Label, Button og
Entry til klassene TkLabel
, TkButton
, and
TkEntry
. Du lager en instans av en widget ved å bruke
new
, som du ville gjort for et hvert annet objekt. Hvis du
ikke angir en forelder til en gitt widget, brukes rotnivå vindusrammen.
Vanligvis ønsker vi å spesifisere forelderen til en gitt widget sammen
med mange andre opsjoner---farge, størrelse og så videre. Vi trenger også
å kunne få informasjon tilbake fra våre widgets mens programmet kjører, ved
å sette opp tilbakekall og delt data.
Hash
.
Du kan gjøre dette i Ruby også, men et alternativ er å sende opsjonene ved
hjelp av en kodeblokk; opsjonsnavnet brukes som et metodenavn inne i blokken
og argumenter til opsjonen viser seg som argumenter til metodekallet.
Widgets tar en forelder som første argument, fulgt av en valgfri hash fylt med opsjoner eller kodeblokken med opsjoner. Dette gjør at de to følgende variantene er ekvivalente.
TkLabel.new(parent_widget) { text 'Hello, World!' pack('padx' => 5, 'pady' => 5, 'side' => 'left') } # or TkLabel.new(parent_widget, text => 'Hello, World!').pack(...) |
padx
og pady
i disse eksemplene) antas å være målt i piksler, men kan også spesifiseres i andre enheter ved å bruke en av de følgende endelsene ``c
'' (centimeter),
``i
'' (inch eller tomme), ``m
'' (millimeter),
eller ``p
'' (punkt).
command
(vist i kallet til TkButton
i neste eksempel) tar inn et Proc
-objekt som vil bli kjørt når en hendelse avfyrer tilbakekallet.
Her bruker vi
Kernel::proc
for å konvertere blokken {exit}
om til et Proc
-objekt.
TkButton.new(bottom) { text "Ok" command proc { p mycheck.value; exit } pack('side'=>'left', 'padx'=>10, 'pady'=>10) } |
TkVariable
som mellomledd.
Dette ser vi i neste eksempel.
Legg merke til hvordan TkCheckButton
settes opp;
dokumentasjonen sier at variable
opsjonen tar en var reference som argument. Vi lager en Tk variabel referanse ved å bruke
TkVariable.new
.
Kaller man så mycheck.value
vil man få tilbake
``0
'' eller ``1
'', beroende på om avkrysningsboksen er avkrysset eller ikke.
Denne mekanismen kan benyttes for enhver ting som størrer var referanser, slik som radioknapper og tekstfelt.
mycheck = TkVariable.new TkCheckButton.new(top) { variable mycheck pack('padx'=>5, 'pady'=>5, 'side' => 'left') } |
configure
, som tar en Hash
eller en kodeblokk, på samme måte som new
. Vi kan forandre det første eksempelet slik at teksten endres når en knapp trykkes:
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
trykkes, vil teksten endre seg umiddelbart fra
``Hello, World!
'' til ``Goodbye, Cruel
World!
''
Du kan også spørre widgets om verdien av spesifikke opsjoner ved å bruke cget
:
require 'tk'
|
||
b = TkButton.new {
|
||
text "OK"
|
||
justify 'left'
|
||
border 5
|
||
}
|
||
b.cget('text')
|
» |
"OK"
|
b.cget('justify')
|
» |
"left"
|
b.cget('border')
|
» |
5
|
Figur 15.2: Pig Latin program skjermbilde |
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 |
Litt på siden: Håndtering av geometrien | |||||||||||||||||
I kodeeksemplene i dette kapittelet vil du ofte se bruk av widget metoden
pack . Det er en viktig metode, viser det seg---dersom du glemmer
å kalle den, får du ikke se din widget. Metoden pack er en kommando
som gir beskjed til kontrolleren som styrer geometrien om å plasse vår
widget i følge de beskrankninger vi har angitt. Tre kommandoer kan sendes
til geometrikontrollere:
pack er den kommandoen som brukes oftest, vil vi holde oss til den i våre eksempler.
|
bind
hos din widget.
La oss for eksempel anta at vi har laget en knapp som viser et bilde.
Vi ønsker at bildet skal endre seg når brukeren har muspekeren over knappen.
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
. Dernest lager vi en knapp (som kalles ``b''
for button), som viser bildet image1
. Så binder vi hendelsen
``Enter'' slik at den dynamisk endrer bildet som vises på knappen til
image2
, og ``Leave'' hendelsen slik at den bytter tilbake til image1
.
Dette eksempelet viser de enkle hendelsene ``Enter'' og ``Leave.''
Ben hendelsen gitt som argument til bind
kan være sammensatt av flere understrenger, separert med bindestrek, av rekkefølgen
modifikator-modifikator-type-detalj.
Modifikatorene er listet opp i Tk referansen og inkluderer
Button1
, Control
, Alt
, Shift
, og så
videre. Type er navnet på hendelsen (tatt utifra navnekonvensjonene
til X11) og inkluderer hendelser som ButtonPress
, KeyPress
,
og Expose
. Detail er enten et tall fra 1 til 5 for
knapper eller en keysym(??) for innput fra tastaturet.
For eksempel, en binding som som vil kjøres når musens første knapp slippes samtidig med at Control tasten holdes inne, kunne spesifiseres slik:
Control-Button1-ButtonRelease
Control-ButtonRelease-1
Selve hendelsen kan inneholde visse felt, slik som tidspunktet og koordinatene til hendelsen. bind
kan sende disse videre til tilbakekallsrutinen ved å bruke hendelsesfeltkoder (event field codes). Disse brukes på samme måte som printf
spesifikasjoner.
For eksempel, for å få tak i x og y koordinatene til en musbevegelse, spesifiserer du kallet til bind
med tre parametre. Den andre parameteren er Proc
-objektet som skal brukes som tilbakekallsrutine, og den tredje parameteren er hendelsens feltstreng.
canvas.bind("Motion", proc{|x, y| do_motion (x, y)}, "%x %y") |
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 |
Figur 15.3: ``We couldn't find the artist, so we had to hang the picture....'' |
TkCanvas
, TkListbox
og
TkText
kan settes opp til å bruke rullegardiner (scrollbars), slik at du kan arbeide med et mindre utsnitt av hele bildet.
Kommunikasjonen mellom en rullegardin og en widget er toveis. Flyttes rullegardinen må den tilhørende widget endre det den fiser frem. Men også når en widget endres, må rullegardinen oppdateres for å vise den nye posisjonen.
Siden vi ikke har brukt lister noe særlig ennå, vil rullegardineksempelet
vårt bruke en rullende liste med tekst. I den neste kodebiten begynner vi
med å lage en ganske alminnelig TkListbox
.
Deretter lager vi en TkScrollbar
.
Rullegardinets tilbakekallsrutine (som settes med command
) vil
kalle listens widgets yview
metode, som endrer verdien til den
synlige porsjonen av listen i y-retningen.
Etter at den tilbakekallsrutinen er satt opp, lager vi den motsatte
bindingen også: når listen føler behov for å rulle, angir vi den passende
rekkevidden til rullegardinet med
TkScrollbar#set
.
Vi kommer til å bruke akkurat denne kodebiten i et fullstendig funksjonelt program i neste avsnitt.
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) }) |
File.new
bruker en blokk for å forsikre seg om at filen blir lukket etter at man er ferdig med å bruke den? Vi kan gjøre en lignende ting med metoden busy
, som vist i det neste eksempelet.
Dette programmet demonstrer også noen enkle manipulasjoner man kan gjøre med en TkListbox
---legge elementer til listen, sette opp et tilbakekall på slipp av musknappen,[Du ønsker sannsynligvis knappeslipp og ikke knappetrykk, da knappetrykkhendelsen selekterer widget.]
og hente ut det nåværende valget.
Inntill nå har vi brukt TkPhotoImage
utelukkende til å vise frem ikoner direkte, men du kan også forstørre, redusere og vise deler av bilder også. Her bruker vi reduksjon til å skalere bildet ned for visning.
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 |
Figur 15.4: Scroll List skjermbilde |
nil
og kalte på søppeltømmeren umiddelbart for å fjerne rasket.
TkWidget
som brukes, og ikke instansen av din klasse.
Perl/Tk: $widget = $parent->Widget( [ option => value ] ) Ruby: widget = TkWidget.new(parent, option-hash) widget = TkWidget.new(parent) { code block } |
Perl/Tk: -background => color Ruby: 'background' => color { background color } |
Perl/Tk: -textvariable => \$variable -textvariable => varRef Ruby: ref = TkVariable.new 'textvariable' => ref { textvariable ref } |
TkVariable
for å koble en Ruby variabel til en variabel i en widget. Du kan da bruke value
tilgangsmetodene i
TkVariable
(TkVariable#value
og
TkVariable#value=
)
for å påvirke innholdet i en widget direkte.
( In progress translation to Norwegian by NorwayRUG. $Revision: 1.9 $ )
$Log: ext_tk.xml,v $ Revision 1.9 2002/10/20 20:09:19 kent skriveleif. Revision 1.8 2002/09/23 19:38:50 kent Første kladd ferdig. Revision 1.7 2002/09/21 13:11:51 kent Nesten frem til canvas med første kladd. Revision 1.6 2002/09/21 09:56:26 kent Frem til geometri håndtering. Revision 1.5 2002/09/16 18:35:24 kent Et par avsnitt, frem til "Getting Widget Data" Revision 1.4 2002/09/14 08:37:30 kent Såvidt begynt.
Forrige < |
Innhold ^
|
Neste >
|