SOP121/ćw - temat E.
Język skryptowy
TCL/TK.
Skrót TCL oznacza "Tool Command
Language".
TCL jest językiem skryptowym, podobnym
do języków powłok Unixa (takich jak ksh, bash, csh). Podstawowym pojęciem
języka jest komenda. Zasadniczo, w tym języku nie ma nic oprócz
komend !. Podstawowym "typem danych" jest string.
Skrót TK oznacza "ToolKit",
czyli bibliotekę do tworzenia okienkowego interfejsu użytkownika, przy
pomocy tzw widgetów, pod XWindows. TK jest dużo łatwiejsze w użyciu
niż biblioteki takie jak np XtIntrinsics !. Jest powszechnie wiadome, że
przy pomocy TK można skonstruować skomplikowany interfejs użytkownika,
w zdumiewająco krótkim czasie ...
Charakterystyczne cechy języka TCL:
Jest językiem interpretowanym (nie trzeba niczego kompilować).
Można pisać tradycyjne skrypty (działające w trybie "tekstowym") - używamy
wtedy interpretera tclsh, lub można
pisać skrypty komunikujące się z użytkownikiem za pomocą okienkowego interfejsu
- używamy wtedy interpretera wish.
Skrypty TCL są przenośne: istnieją interpretery dla dowolnego Unixa, oraz
dla platformy W95/NT.
Język TCL można rozszerzać na różne sposoby. Rozszerzanie polega zasadniczo
na dodawaniu nowych komend. Można to robić z poziomu skryptu (komenda "proc")
a także z poziomu języka C/C++ (nowe komendy wbudowane).
Istnieją mechanizmy ułatwiające używanie dużych rozszerzeń (zawierających
wiele komend). Podstawowym rozszerzeniem TCL-u jest TK. Istnieje wiele
innych rozszerzeń: BLT, TIX, ...
Można "zintegrować" TCL z aplikacją. TCL musi wtedy zostać rozszerzony
o komendy pozwalające sterować aplikacją. TCL staje się wtedy językiem
do komunikacji między aplikacjami (jedna aplikacja może wysłać drugiej
skrypt do wykonania, następnie druga aplikacja wykonuje skrypt, następnie
rezultat działania skryptu jest zwracany pierwszej aplikacji).
Filozofia dwujęzykowego tworzenia aplikacji: najpierw rozszerzamy TCL o
odpowiednie "cegiełki", konkretne aplikacje są skryptami, zbudowanymi z
owych cegiełek.
Istnieje potężne narzędzie do automatycznego przetwarzania źródeł danej
biblioteki (w j. C/C++) na rozszerzenie TCL-u. Jest to program SWIG.
Rozszerzenie zawierające bibliotekę OpenGL zostało zrobione właśnie w ten
sposób !.
Aplety TCL/TK. Jeśli mamy odpowiednią wtyczkę (plug-in) do Netscape,
to możemy umieszczać aplety w stronach, przy pomocy polecenia <embed
plik.tcl>. Istnieją bardzo wyrafinowane mechanizmy bezpieczeństwa !.
Tradycyjnie, TCL/TK jest używane do unowocześniania "starych" aplikacji,
takich jak np klient "ftp", wymagający wydawania komend open, get itp. Przy
pomocy TCL/TK można z niego zrobić nowoczesną aplikację, komunikującą się
z użytkowinikiem przy pomocy okienek, listbox-ów, scrollbar-ów itp ...
Podstawy języka TCL.
Podstawowym pojęciem TCL-u jest komenda. Program (skrypt) w TCL-u
to po prostu tekst zawierający ciąg komend. Także instrukcje sterujące
(np pętle) są w rzeczywistości komendami ...
Dokumentacja TCL-TK:
[Unix] jeśli zainstalowano "tclX", to wygodny help jest dostępny przez
program "tclhelp"; ponadto opisy komend są dostępne także w zwykłym manualu
[rozdział "n"]; strony manuala znajdują się w katalogu /usr/share/man/mann
(stad można brać nazwy komend Tcl-u)
[WinNT] help znajduje się w pliku
"g:\app\dev\Tcl\doc\tcl82.hlp" (?)
oto prosta dokumentacja, jednej ze starszych wersji TCL
jeszcze inna dokumentacja "http://hermes.desy.de/tcl"
Dokumentacja "ActiveTcl"; jest to Tcl v.8.4 z wieloma rozszerzeniami ...
http://ASPN.ActiveState.com/ASPN/docs/ActiveTcl
Inne strony WWW poświęcone językowi TclTk :
http://www.tcltk.com (?)Sposoby uruchamiania skryptów w
TCL-u:
interpreter TCL-u posiada konsolę, z której można uruchamiać dowolne
komendy; w szczególności skrypty można uruchamiać przy pomocy komendy "source skrypt.tcl"
[Unix] należy wydać z xterm-u polecenie "wish" lub "tclsh" (bez parametrów);
w xterm-ie z którego uruchomiliśmy interpreter pojawi się konsola
[WinNT] jak wyżej, z tym że interpreter znajduje się w pliku "g:\app\dev\Tcl\bin\wish82.exe"
i "g:\app\dev\Tcl\bin\tclsh82.exe"; po uruchomieniu pojawia się osobne
okienko z konsolą; skrypty można uruchamiać poleceniem "source"
lub przy pomocy menu "File" (tylko "wish")
skrypt w TCL/TK zawierający udoskonaloną konsolę: konsola.tcl
inne metody uruchamiania skryptów ...
[Unix] można nadać plikowi ze skryptem prawo "x" oraz w pierwszej linii
skryptu umieścić jedno z dwóch:
#!/usr/bin/wish
#!/usr/bin/tclsh
[Unix] można wydać następujące polecenie aby uruchomić "skrypt.tcl":
wish skrypt.tcl
tclsh skrypt.tcl
Debuger TCL/TK
(raczej dla zaawansowanych !):
W pliku "tdebug.zip"
znajduje się debuger który działa na wszystkich platformach (jest
napisany w TCLu).
Sposob uruchamiania debugera jeśli szukamy błędu
w "plik.tcl":
wish tdchoose.tcl plik.tcl
Można wykonywać krokowo jedynie procedury (zdefiniowane przez "proc");
należy je wcześniej wskazać w odpowiednim okienku; nie można debugować
procedur obsługujących asynchronicznie pliki.
Zadanie 70
Naucz się języka TCL/TK wypróbowując poniższe przykłady (dłuższe z
nich należy umieścić w skrypcie !).
Komendy oraz wydruki ich działania umieść
w sprawozdaniu !.
Prosty przykład skryptu:
# komentarz
#
set iloscObrotow 10
# przypisywanie zmiennej "iloscObrotow" wartości "10"
for {set i 1} {$i <= $iloscObrotow} {incr i} {
puts "<<<$i>>>"
# "puts" wyswietla napisy na terminalu
}
Substytucje komend.
Każda komenda zwraca, po uruchomieniu, string.
Jeśli w tekście skryptu zamieścimy komendę w nawiasach [], to komenda
zostanie uruchomiona, a jej wynik zostanie wstawiony w miejsce napisu [komenda].
Przykład:
puts "wynik operacji 1+1 = [expr 1+1]"
# "expr" to komenda do obliczania wartości wyrażeń arytmetycznych
# wynik: wynik operacji 1+1 = 2
Substytucje zmiennych.
Substytucje zmiennych to zastępowanie napisu "$nazwa_zmiennej" wartością
tej zmiennej.
Przykład:
set zmienna1 "qqq www eee"
set zmienna2 {qqq www eee}
puts "zmienna1=$zmienna1, zmienna2=$zmienna2"
Zmienne, tablice.
Wszystkie zmienne są stringami.
Nadawanie wartości "zmiennym prostym":
set zmienna1 "qqq www eee"
set zmienna2 {qqq www eee}
set zmienna3 123
set zmienna4 qwe
set zmienna4
# wynikiem tej komendy jest wartość zmiennej "zmienna4"
puts "zmienna4=$zmienna4"
puts "zmienna4=[set zmienna4]"
# powyższe 2 linie robią, mniej więcej, to samo
Usuwanie zmiennych:
unset zmienna1 zmienna2
Nadawanie wartości elementom tablic:
set tab1(1) qqq_1
set tab1(2) qqq_2
set tab1(xxx) qqq_xxx
# tablice są asocjacyjne - indeks nie musi być liczbą !
puts "$tab1(xxx), $tab1(1)"
parray tab1
# procedura "parray" wypisuje elementy tablicy
set indeksy_tab1 [array names tab1]
# polecenie "array names" zwraca indeksy elementów tablicy
foreach x $indeksy_tab1 {
puts "tab1($x)=$tab1($x)"
}
UWAGA: Nie powinno się tworzyć skomplikowanych struktur danych z poziomu
skryptu (gdyż języki skryptowe nie do tego są przeznaczone) !. Natomiast
rozszerzenia TCL-u, pisane w języku C, mogą używać wewnętrznie skomplikowanych
danych.
Stringi, cytowanie.
Cytowanie to wyłączanie specjalnego znaczenia niektórych znaków w stringu
(tak aby interpreter ich nie interpretował, tylko traktował dosłownie).
Cudzysłowy "" cytują słabiej, natomiast {} cytuje mocniej. Można także cytować
1 znak przy pomocy \
set x 123
puts "pwd=[pwd], \$x=$x"
# pwd to polecenie pokazujące bieżący katalog
# wynik: pwd=/home/faculty/mhanckow, $x=123
puts {pwd=[pwd], \$x=$x}
# wynik: pwd=[pwd], \$x=$x
UWAGA: wydaje się, że w poniższym przykładzie mamy instrukcję sterującą,
w rzeczywistości jest to zwykła komenda z czterema parametrami (które są
stringami !):
for {set i 1} {$i <= 10} {incr i} {
puts "<<<$i>>>"
}
Jednak działanie tej komendy jest takie jakiego byśmy się spodziewali.
UWAGA: w językach skryptowych często przygotowuje się "kod" w postaci stringu, a następnie ten kod jest wykonywany
ja na przykładzie:
set x1 {set i 1}
set x2 {$i <= 10}
set x3 {incr i}
set x4 {puts "<<<$i>>>"}
# trzeba użyć {}, gdyż substytucja wartości zmiennej "i"
# ma się wykonywać dopiero w czsie działania pętli
for $x1 $x2 $x3 $x4
Listy.
Często stringi można interpretować jako listy. Jest wiele poleceń dotyczących
operacji na listach (ich nazwy zaczynają się od literki "l" !).
info commands l*
# wyswietla komendy, których nazwy zaczynają sie od "l"
set l1 {qqq www eee rrr}
foreach el $l1 {
puts $el
}
Listy mogą być dowolnie zagnieżdżane:
set l2 {qqq www {1 2 3 444 {q w e r} sss ddd} rrr}
foreach el $l2 { puts $el }
puts [lindex [lindex [lindex $l2 2] 4] 1]
# elementy listy są numerowane od 0;
# to polecenie powinno wyswietlic "w"
"Instrukcje" sterujące.
set x 10; set y 11
if {$x <= $y} then {puts tak} else {puts nie}
# w warunku nie trzeba używać "expr" !
if {$x+1 <= $y+1} then {puts tak} else {puts nie}
# priorytety operatorów w wyrażeniach:
# patrz polecenie "expr" (podobne do j. C)
if {$x+1 <= $y+1} {puts tak} {puts nie}
# można opuszczać niektóre "słowa kluczowe"
if {$x <= $y} then {
puts tak
} else {
puts nie
} # uwaga na sposób zapisu w wielu liniach
# nawias { MUSI byc w poprzedniej linii
# --- petle ---
set x 0
while {$x<10} {
puts "x is $x"
incr x
}
for {set x 0} {$x<10} {incr x} {
puts "x is $x"
}
set x {}
foreach {i j} {a b c d e f} {
lappend x $j $i
# lappend dołącza podane elementy na koniec listy
# ktorej nazwa jest podana przez 1 argument
}
# The value of x is "b a d c f e"
# There are 3 iterations of the loop.
Ważniejsze komendy TCL-u.
expr - obliczanie wyrażeń arytmetycznych (i nie tylko)
regexp - sprawdzanie czy napis jest zgodny z "wyrażeniem regularnym"
info - odczytywanie rozmaitych informacji
array - operacje na tablicach asocjacyjnych
string - operacje na stringach
gets/puts/open/close/read/file/glob - operacje na plikach
Definiowanie procedur.
proc mojaProc {param1 param2} {
puts "$param1, $param2"
}
mojaProc 111 222
# wywołanie procedury
proc Silnia {liczba} {
if {$liczba <= 1} then {
return 1
} else {
return [expr {[Silnia [expr {$liczba-1}]] * $liczba}]
#return [expr [Silnia [expr $liczba-1]] * $liczba]
# tak tez dziala, ale wolniej!
}
}
Silnia 10
Rozszerzenie TK.
TK służy do tworzenia "okienkowego" interfejsu użytkownika.
Używamy interpretera "wish" lub "wish8.?". Po jego uruchomieniu
pokazuje się główne okno oraz konsola, w której można wprowadzać komendy.
Podstawowe pojęcia.
widget
Widgety to okienka przystosowane do konkretnego celu np do wyświetlania
etykiety lub do wprowadzania napisu (w Visual Basic-u występują pod nazwa
kontrolek).
Są następujące klasy widgetów: Label, Entry, Button, Frame, Listbox,
Menu, Text, Canvas, Toplevel ... i wiele innych. Konkretny widget jest
obiektem danej klasy.
drzewo widgetów
Widgety tworzą drzewo widgetów. Do elementów tego drzewa odwołujemy
się podobnie jak do elementów drzewa katalogów (zamiast "/" uzywamy znaku
"."). Zasadniczo, podwidgety nie powinny wychodzić poza obszar swojego
widgetu macierzystego.
Sama kropka oznacza głowne okno. W poniższym przykładzie tworzymy widget
klasy Label, będący podwidgetem głównego okna:
label .l1 -text "Etykieta .l1"
(na razie tego widgetu jeszcze nie widać, trzeba je "umieścić" !)
-
umieszczanie widgetów
Aby widget stał się widoczny, należy go umieścić, przy pomocy
pewnego zarządcy geometrycznego. Mamy do dyspozycji kilku takich
zarządców: pack, place, grid.
Najczęściej używa sie polecenia "pack":
pack .l1
-
opcje widgetów; komenda widgetowa
Opcja -text "..." określa jaki tekst będzie wyświetlany w widgecie
".l1". Jest bardzo wiele takich opcji; patrz man label !.
Opcje widgetu można podać w czasie tworzenia widgetu (jak w powyższym
przykładzie), Można je potem zmieniać przy pomocy komendy widgetowej.
Po utworzeniu widgetu ".l1", powstaje komenda widgetowa o nazwie ".l1".
Widget można konfigurować (zmieniać wartość opcji) przy pomocy podkomendy
"config" komendy widgetowej;
.l1 config -text "!!! Etykieta .l1 !!!"
Inny przykład konfigurowania: określamy styl i grubość ramki wokół widgetu:
.l1 config -relief raised
.l1 config -borderwidth 0.5cm
Zarządca geometryczny "pack" oraz widget "frame"
Widget "frame" służy zasadniczo tylko do "hierarchicznego organizowanie"
widgetów w drzewie widgetów:
frame .f_a
frame .f_b
label .f_a.l1 -text "Etykieta .f_a.l1"
label .f_a.l2 -text "Etykieta .f_a.l2"
pack .f_a.l1 -side left
pack .f_a.l2 -side left
label .f_b.l1 -text "Etykieta .f_b.l1"
label .f_b.l2 -text "Etykieta .f_b.l2"
pack .f_b.l1 -side left
pack .f_b.l2 -side left
pack .f_a
pack .f_b
Odpowiednie opcje polecenia "pack" pozwalają sterować sposobem umieszczania
podwidgetów w widgecie macierzystym. Na rysunku poniżej widać, gdzie są
umieszczane widgety jeśli użyliśmy opcji "-side left" polecenia "pack"
następująco:
label .l1 -text "Etykieta .l1" -relief raised -borderwidth 0.2cm
label .l2 -text "Etykieta .l2" -relief raised -borderwidth 0.2cm
label .l3 -text "Etykieta .l3" -relief raised -borderwidth 0.2cm
pack .l1 -side left
pack .l2 -side left
pack .l3 -side left
# widgety będą wstawiane po lewej stronie "wydrążenia"
# każdy widget ma swoją "parcelę"
Gdybyśmy użyli opcji "-fill y" do polecenia "pack .l3" efekt byłby jak
na rysunku poniżej (.l3 zajmie całą swoją parcelę !).
pack .l3 -side left -fill y
Gdybyśmy użyli opcji "-expand yes" lub "-expand 1" do polecenia "pack
.l3" efekt byłby jak na rysunku poniżej (parcela .l3 zajmie całe wydrążenie
!).
pack .l3 -side left -expand yes -fill none
# spróbuj także:
pack .l3 -side left -expand yes -fill y
pack .l3 -side left -expand yes -fill x
UWAGA: łącząc widgety "frame" i opcje komendy
"pack" można tworzyć dowolnie skomplikowane okna. Ich wzajemne rozmieszczenie
jest w dużym stopniu ustalane automatycznie !.
Widget "entry".
Służy do wprowadzania tekstu (pojedyncza linia tekstu).
Widget "button".
Tworzy guzik, którego naciśnięcie powoduje uruchomienie skryptu podanego
przez opcję "-command".
Widget "scrollbar".
Tworzy suwak; suwak ten może być w prosty sposób skojarzony z innym widgetem,
np:
entry .e -xscroll ".s1 set"
scrollbar .s1 -command ".e xview" -orient horizontal
#lub
listbox .lb -yscroll ".s2 set"
scrollbar .s2 -command ".lb yview"
Widget "listbox".
Widget typu "listbox" zawiera listę elementów; zazwyczaj jest związany
z suwakiem.
Wstawianie elementów do listbox-u:
listbox .lb
pack .lb -side left -fill y
.lb insert end "qqqqqqqqq1"
.lb insert end "qqqqqqqqq2"
.lb insert end "qqqqqqqqq3"
W powyższym przykładzie słowo "end" oznacza miejsce w którym są wstawiane
do listbox-u nowe elementy. Można wstawiać w dowolne miejsce (patrz
dokumentacja polecenia "listbox").
Widget "text".
Tworzy okienko pozwalające edytować tekst (w wielu liniach).
Przykład:
text .t; pack .t
set plik [open "plik.txt" "r"]
# otwarcie pliku
.t insert end [read $plik]
# wstawienie zawartości pliku do okienka tekstowego
close $plik
# zamknięcie pliku
puts -nonewline "zawartosc = [.t get 1.0 end]"
# odczytanie zawartości okienka tekstowego
Komenda widgetowa "get" wymaga indeksów początku i końca tekstu, który
zamierzamy odczytać; napis 1.0 to początek tekstu ("nr_linii.nr_znaku";
jak widać linie numeruje się od 1, a znaki od 0 !).
Widget "canvas".
...............................
...............................
Ważniejsze komendy TK.
bind widget sekwencja_zdarzeń skrypt
Komenda "bind" definiuje procedurę obsługi zdarzenia dla danego widgetu
(zobacz także do dokumentacji). Niech ".lb" będzie listbox-em:
bind .lb <Double-Button-1> {puts "Button-1 [.lb get active]"}
Powyższy przykład definiuje reakcje na dwukrotne kliknięcie myszą na którymś
z wierszy listbox-u ".lb"; treść tego wiersza jest wyświetlana na konsoli.
bind .lb <Return> {puts "Return [.lb get active]"}
Powyższy przykład definiuje reakcje na naciśnięcie klawisza Return.
...................................................
Zadanie 71
Przy pomocy widgetów "frame" i polecenia "pack", a także widgetów "label"
i "entry" utwórz następujące okienko:
Imie |---------|
Nazwisko |---------------------|
Adres |---------------|
Guzik
Symbol |---| oznacza pole do wprowadzania danych widgetu "entry"; okienka
NIE muszą być wyrównane tak jak to zostało narysowane. Guzik powoduje wyświetlenie
wprowadzonych napisów (patrz przykład "np02.tcl"
i komenda tk_dialog).
Ćwiczenie 72
Uruchom poniższe przykłady i obejrzyj ich kod.
Prosty przykład z guzikiem: "np02.tcl".
Przykład "np07.tcl". Są tam tworzone 3 okienka
dialogowe z formularzami. Widgety "entry" w formularzach używają tych samych
zmiennych do przechowywania zawartości, dlatego gdy coś wpiszemy do w jedym
okienku, to natychmiast pojawia się w pozostałych. Na tym przykładzie widać,
że tworzenie okien warto wspierać procedurami !!!.
Przykład "np16.tcl". Zastosowanie widgetów "radiobutton"
i "checkbutton".
Przykład "np19.tcl". Edycja pozycji tabeli, przy
pomocy wielu okienek dialogowych.
Przykład "np13.tcl". Program do porównywania
fontów. Otwiera 3 okienka dialogowe. W każdym widać listbox z nazwami dostępnych
fontów, a na dole wygląd literek ABC, w bieżącym foncie.
Przykład "np29.tcl"+("scrolled.tcl"
). Program pokazujący dużą tablicę rysunków. Z tej tablicy widać tylko
małe okienko, ze scrollbar-ami pozwalającymi je przesuwać (scrolled.tcl).
Przykład "np26.tcl"+("scrolled.tcl"
). Program pokazuje tablicę dość złożonych elementów ("entry" ze scrollbar-em).
Z tej tablicy widać tylko małe okienko, ze scrollbar-ami pozwalającymi
je przesuwać (scrolled.tcl).
Skrypt demonstracyjny "widget", który znajduje się w katalogu:
/usr/lib/tk8.0/demos/widget
# dotyczy Unix-a
g:\app\dev\Tcl\lib\tk8.2\demos\widget.tcl
# dotyczy WinNT
trzeba wejść do tego katalogu (polecenia "cd", "pwd") z poziomu konsoli,
a następnie uruchomić skrypt poleceniem "source"
Zadanie 73
Napisz skrypt imitujący "Nortona Commandera", tj pozwalający chodzić
po drzewie katalogów, i ewentualnie wykonywać jakieś operacje (np oglądanie
zawartości pliku lub uruchamianie programów). Podstawowym widgetem, którego
należy użyć, będzie oczywiście "listbox" (patrz manual lub help). Polecenie
wypisujące pliki z bieżącego katalogu to "glob *", polecenia do chodzenie
po drzewie katalogów to "cd" i "pwd". Przydatne będą także: "file" i "exec".
Zadanie 74
Zaprogramuj prosty edytor tekstu. Powinien mieć guziki "Otwórz"
do wybierania pliku (użyj polecenia tk_getOpenFile) oraz "Zapisz" do uaktualniania
zmian. Pod guzikami powinna być widoczna nazwa pliku, a pod nią zawartość
pliku w widgecie "text". Widget "text" powinien mieć pionowy i poziomy
suwak.
Zadanie 75 (*)
Zaimplementuj "kulę bilardową". Kula ta porusza się po głównym
oknie i odbija się od jego ścian pod tym samym kątem pod którym w nie uderzyła.
Wszystko to ma działać w tle (jest możliwe wydawanie innych poleceń).
Wskazówki:
Obrazek przedstawiający kulę można pokazywać przy pomocy widgetu "label":
set i [image create photo -file pilka.gif]
label .l -image $i
Jednak widget ".l" musi być umieszczany przy pomocy polecenia "place" (a
nie "pack"):
place .l -x $x -y $y
Wysokość i szerokość widgetu ".l" można odczytać poprzez:
set w [winfo width .l]
set h [winfo height .l]
Wysokość i szerokość głównego okna (oraz jego przesunięcie wzg ekranu)
można odczytać:
scan [winfo geometry .] "%dx%d+%d+%d" gw gh gx gy
# polecenie "scan" pozwala wyciągnąć potrzebne wartości z tekstu;
# powstaną zmienne o nazwach "gw" "gh" "gx" "gy"
Wykonywanie się skryptu "w tle" można osiągnąć następująco:
set skrypt {puts "!!!"; after 2000 $skrypt}
# "after" powoduje wykonanie danego skryptu
# po zadanej liczbie milisekund.
eval $skrypt
# wykonanie skryptu zawartego w zmiennej "skrypt"
Zadanie 76
Skrypty "sms1.tcl" i "sms2.tcl"
pomagają przy wysyłaniu sms-ow; pierwszy skrypt wysyła sms-y bezpośrednio,
drugi tworzy skrypt "ksh" ktorego uruchominie spowoduje wysłanie sms-ow.
Niezbędny jest skrypt o nazwie "sms_do_XY", który faktycznie wysyła sms
pobrany z stdin (desk 0). Treść smsów wprowadza się do linii o nr 1-15.
Kazda linia zaczyna sie od specjalneg nagłówka "(MH??)". Gdy zostanie przekroczona
długość 100 znaków jest to w pewnien sposób sygnalizowane. Do kopiowania/przenoszenia
tekstu między liniami służą klawisze Ctrl-X ("Cut"), Ctrl-C ("Copy"), Ctrl-V
("Paste"). Aby się dowiedzieć w którym miejscu "złamać" linię, wystaczy
cofnąc kursor.
Co należy zrobic ? Wypróbuj te skrypty (a przynajmniej SMS2).
Powiedz w jaki sposób jest sygnalizowane przekroczenie długości linii i
miejsce w którym należy złamać linię. Wstaw fragment skryptu "ksh" wysylającego
smsy utworzony przez SMS2. Dodaj dodatkowe okienko "entry" w ktorym podaje
sie inicjaly umieszczane na poczatku każdej linii tekstu.
Zadanie 77
(Czat graficzny).
Wypróbuj skrypty "czat4_ser.tcl" i "czat4b_kli.tcl";
są to serwer i klient usługi czat graficzny udostępniającej wspólną
tablicę do rysowania oraz wspólne okienko tekstowe ("wspólne" <=> dostępne dla
wielu użytkowników w sieci). Wypróbuj działanie czata graficznego uruchamiając
zarówno serwer jak i klientów na lokalnej maszynie. Narysuj coś, wpisz jakiś
tekst do okienka tekstowego, następnie wyłącz klientów; do sprawozdania wstaw
fragment pliku "canvas.txt" w którym serwer przechowuje stan tablic (robi to na
wypadek awarii).
Standardowo usługa czat graficzny działa na lokalnej
maszynie; wykonaj eksperyment w którym klienci będą się podłączać z innych
komputerów (trzeba będzie zmienić pewne zmienne w skryptach klientów !).
Pojęcia dotyczące sieci komputerowych (potrzebne aby zrozumieć działanie
skryptów "czat4*.tcl") :
- model klient/serwer
- adres IP maszyny;
jest to liczba 32 bitowa (4 bajty), często przestawiana w postaci "kropkowej",
np 1.1.1.2
- port;
jest to liczba całkowita; na tej samej maszynie może być kilka serwerów
czekających na klientów na różnych portach
- połączenie TCP
- gniazda BSD
Pojęcia/ idee dotyczące Tcl/Tk:
- widget "canvas"
widget dający skryptom Tcl/Tk możliwości graficzne (np rysowanie linii)
- komenda "socket"
komenda ta służy do komunikacji przez sieć przy pomocy protokołu TCP;
komenda ta ma dwa zasadnicze sposoby uruchamiania:
# po stronie klienta
---------------------------------------------
set sock [socket adres_IP_serwera port_serwera] #
podłączamy się do serwera
puts $sock "tra la la"
# po stronie serwera
-------------------------------------------
socket -server proc_obsługi_klienta port # instalujemy
proc obsługi klientów
proc proc_obsługi_klienta {s addr port} {
set linia [gets $s]
puts $s "dostałem od ciebie $linia"
}
- na jakiej zasadzie działa czat graficzny
informacje w modyfikacjach obrazka lub tekstu są natychmiast przesyłane do
wszystkich innych klientów (i modyfikacje są wykonywane) - dzięki temu każdy
klient ma identyczną kopię obrazka i okienka tekstowego
(koniec zadania 77)
Zadanie 78
(Eksperymenty z widgetem canvas).
Napisz skrypt tworzący następujące okienko:
Mamy tutaj
następujące elementy:
- widget canvas zaopatrzony w suwaki pionowy i poziomy ...
frame .fff
canvas .fff.ccc -width 10c -height 5c \
-scrollregion "0c 0c 15c 15c" \
-yscrollcommand ".fff.s1 set" \
-xscrollcommand ".fff.s2 set"
scrollbar .fff.s1 -command ".fff.ccc yview"
scrollbar .fff.s2 -command ".fff.ccc xview" -orient
horizontal
pack .fff.s1 -side right -fill y
pack .fff.s2 -side bottom -fill x
pack .fff.ccc -side left
- na canvas-ie ".fff.ccc" umieszczono kilka elementów przy pomocy komendy
widgetowej
.fff.ccc create typ_elem_graf x1 y1 [x2 y2]
pozostałe_opcje
następujący kod:
for {set i 0} {$i <= 5*10} {incr i 2} {
set id [.fff.ccc create line
0c 0c 5c ${i}m -width 1]
if {$i <=5*10/2} then {
.fff.ccc
addtag "qqq" withtag $id
}
}
tworzy widoczne na obrazku linie, przy czym połowie z nich przypisuje etykietkę
(tag) "qqq"; dzięki temu będzie można wykonywać operacje grupowe na wszystkich
obiektach graficznych z tą etykietką !
- ponadto na canvas-ie utworzono elementy graficzne typu:
tekst:
.fff.ccc create text 5c 1.5c -text "text !!!!!!!!!!!!" -font
{Arial 30}
prostokąt:
.fff.ccc create rectangle 1c 0.5c 2c 1c -fill #808080
window (widget dowolnego rodzaju utworzony wcześniej):
frame .eee
entry .eee.e1; .eee.e1 insert end "11111111"
entry .eee.e2; .eee.e2 insert end "22222222"
pack .eee.e1 .eee.e2
.fff.ccc create window 5c 3c -window ".eee"
entry .fff.ccc.eee
.fff.ccc.eee insert end "333333333"
.fff.ccc create window 5c 4c -window ".fff.ccc.eee"
(czym się różnią dwa pierwsze widgety entry od trzeciego ? - przesuń je suwakiem
poza canvas ...)
- guziki w dolnej części okna modyfikują (grupowo) elementy elementy z
etykiektą "qqq":
# kod zmieniający grubość linii (na przemian 1 lub 3)
set w [.fff.ccc itemcget "qqq" -width]
if {$w>1} then {set w 1} else {set w 3}
.fff.ccc itemconfigure "qqq" -width
$w
}
# kod zmieniający skalę linii
.fff.ccc scale "qqq" 0c 0c 1.2 1.2
Dodaj do canvas-u jeszcze kilka elementów graficznych, o których przeczytasz
w help-ie/ manualu polecenia canvas.
Zadanie 78a
(Zastosowanie canvas + elem. graf. window).
Napisz skrypt tworzący coś w rodzaju wielkiego "arkusza kalkulacyjnego", którego
fragment widzimy w małym okienku. Okienko to możemy przesuwać po arkuszu przy
pomocy suwaków.
Wskazówka: użyj widgetu canvas z elementem graficznym typu window
zawierającym widget frame w którym znajduje się "arkusz" utworzony z widgetów
entry + frame. Do komórek arkusza wstaw początkową wartość w postaci "wiersz X
kolumna". W razie problemów patrz przykład "np29.tcl"+"scrolled.tcl"
.