Tcl/tk (parte I)
BAKUNIN
bakunin@meganmail.com
Immaginate un programma patch di DOS, immaginate la completezza del linguaggio C, immaginate la grafica di Windows o di Linux con KDE e GNOME, immaginate tutto ciò come creabile attraverso un linguaggio semplice, gratis, e funzionale ...
No! Non è un sogno. Tutto ciò esiste e si chiama TCL/TK! Un nuovo (più o meno) linguaggio che in brevissimo tempo conquisterà presto anche voi. Tutto ciò grazie ad una semplicità sfrenatamente esagerata ...
Ovviamente questo non può essere della Microsoft, ed infatti non lo è. Se quindi non girate sotto LINUX, beh... ci risentiamo fra un po' di anni quando Billy e il suo Windozzo sarà solo un brutto ricordo!!! Non è detto però! Probabilmente con un po' di ricerca troverete la versione per Windows. Esiste, ne sono sicuro e (update del 09/04) l'ho trovato. La versione per Windows la trovate nella sezione Programmi nella sezione Programmare.
Se comunque girate sotto Linux (e se non lo fate leggete e convincetevi a cambiare idea!) conoscete quei simpatici programmini detti scripts che non sono altro che comandi in sequenza come per il DOS. Come per il DOS?!? Non proprio perché questi sono veri e propri programmi! Hanno una struttura compressa, ruotano su vari linguaggi, sono veloci e affidabili. Pensate che questi scripts funzionano (se scritti in PERL, [che prima o poi vi spiegherò...] anche su internet...). Se li conoscete preparatevi a vederli come non li avete mai visti prima...
Se pensate a Linux come un ambiente brutto e oscuro che si basa su shell (come quelle che sono su internet...) non avete quasi per nulla capito! Linux funziona anche in ambiente grafico a 32 bit puri come (e probabilmente meglio) Windows e proprio qui ora creeremo.
"MA COSI' IO CHE HO WINDOZZ E NON HO TROVATO IL TCL/TK MI SPARO?!?" Ebbene NO! Infatti questo ambiente è MultiPiattaforma indi per cui si può usare indiscriminatamente su Windows e Linux. Quindi no problema ... Un giorno magari vi spiegherò come usarlo indiscriminatamente ... ma per ora, seguite!
Come forse voi sapete, il "programma" che permette la grafica in Linux si chiama X-Window (mi raccomando! Senza S finale). X-Window è nato circa 10 anni fa quando nei laboratori del MIT fu creato il primo bozzetto di quel programmino, che, non vorrei dire ma, WindowsSS ha un po' da invidiare. Infatti, fu creato da 11 produttori di software e hardware a livello mondiale gratuitamente. Nacque quindi nel 1987 l'X11R1, un consorzio internazionale. Comunque, dopo questa pizzosa parentesi storica, passiamo ai fatti, cioè:
- Non è un programma, ma un insieme di protocolli, che gestisce in maniera quasi del tutto autonoma la CPU, la RAM e il disco. Tutto si basa grazie al server TCP/IP. Non centra assolutamente però con il funzionamento della rete, anzi questi servers sono solo di architettura.
- Leggete un po': Mediamente Windozz e similari programmi con la preceduti dalla parolina "Microsoft" vengono eseguiti dalla CPU da singole postazioni di lavoro, qui invece tutto è rovesciato, nel senso che è il server remoto ad eseguire i programmi, mentre il CPU ha il compito solo di visualizzare. Sta di fatto (per quelli che non ci stanno già capendo più niente) che è l'ambiente X che fa le regole e le gestisce. Rivoluzione del SISTEMA!!!
Altro aspetto dell'ambiente X (che è il diminutivo di X-Window), è STARTX questo funge grazie a il file XF86Config che viene impostato dal programma xf86config (notate che qui le maiuscole e le minuscole sono lettere totalmente diverse). Qui io lo cito e basta. Se volete spiegazioni migliori sull'impostazione e la configurazione ci sono 2 scelte: 1 leggerla nella zona LINUX (che per ora non esiste ancora!) del sito go.to/tankcommandos oppure mailatemi... Sta di fatto che poi ci sono altri file tipo .xinitrc e .fvwmrc e similari, che hanno uno scopo che... e inutile che ve lo spieghi qui!
Sappiate comunque che STARTX e file vari sopra citati permettono il corretto funzionamento dell'ambiente X. Indi per cui sono prima o poi da capire bene. Ma per ora io vi spiego solo come programmare! Quindi, ancora un po' di pazienza. Mi dimenticavo di dirvi che ci sono vari ambienti grafici (i più famosi sono KDE, GNOME, AfterStep, ecc..) che girano tutti sotto ambiente X.
Ora però vi racconto un po' di storia su questo ambiente, perché rasenta la leggenda! Immaginatevi un tipo di nome John Ousterhout, studente alla facoltà di ingegneria informatica (credo, ma comunque sempre informatica era...) che al posto di comportarsi come gli studenti normali, si trasferisce su Linux, se ne innamora e prima di finire l'università scrive il suo PRIMO LINGUAGGIO DI PROGRAMMAZIONE!!! Sì! Si è scritto un linguaggio, appunto il TCL e poi è stato accoppiato al TK, formando il TCL/TK. Come dire! Un genio. Non ci chiediamo poi perché la SUN la prelevato facendone uno dei principali esponenti della mitica produttrice si software per LINUX. Ovviamente questo è successo nel lontano 1989, ma da qui in avanti, questo programma ha avuto miriadi di modifiche fino ad arrivare alla versione 8, totalmente gratuita! Sembra che la versione più stabile sia la TCL/TK 7.6/4.2 ma, io parlerò della 8.0 perché, è quella che ho installato e che ritengo più semplice e creativa. Soprattutto non vi crediate di riuscire a incriccare il programma. Non è la versione più stabile, ma prima di far cashare il programma, altro che questa guida vi serve!
Ho parlato un po' di tutto, e penso che questa introduzione ora deve finire! Quindi incomincio subito col dirvi:
Credete che vi abbia preso in giro su fatto della semplicità? Provate a fare questo:
Aprite un editor qualsiasi e create il file prova.tcl con le seguenti righe di codice:
--------INIZIO---------
#!/usr/bin/wish
label .msg -text "Ciao MAMMA!!"
button .bye -text "CIAO" -command {exit}
pack .msg .bye
----------FINE---------
Poi uscite e rendete il file eseguibile attraverso il comando:
chmod +x prova.tcl
e poi fatelo partire, ovviamente in ambiente X con il comando:
prova.tcl
e guardatevi lo spettacolo!
Spiegazione a dopo.
INDICE
- Installazione
- Regole
- Scrivere, commentare, ecc..
- Variabili e simili
- Stringhe e simili
- Cicli
- Procedure
- File
- Esecuzione comandi
- GRAFICA!!!
- a) Etichette
- b) Frame
- c) Input
- d) Pulsanti
- e) Disegni
- f) PACK
- g) Listbox
- h) Eventi
- Cose carine
- TCL/TK e internet
- Creare un database
1. Installazione
Per installare tcl/tk bisogna avere le sorgente. Ma prima d'installare controllare di averlo non farebbe certo male. Le uniche possibilità che vi impediscono di averlo è avere una versione di LINUX risalente a più di 2 anni fa. Comunque per installarlo bisogna avere il codice sorgente. Queste si possono scaricare al sito http://sunscript.sun.com . Io vi consiglio quelle 8.0. Entrate come utente root ed eseguire da prompt i seguenti comandi:
tar .zxf nome_dei_file.tar.gz
I file saranno due: tcl8_0p2.tar.gz e tk8_0p2.tar.gz (i nomi potrebbero non corrispondere!) e quindi bisogna fare l'operazione 2 volte.
Poi entrare nella directory creata e fare:
configure
make
make install
Facciamo gli stessi comandi nella seconda directory creata. Dovrebbero essersi crate le directory /usr/local/lib le librerie tcl/tk mentre i binari saranno nella directory /usr/bin.
Ora facciamo:
ln -sf /usr/local/bin/tclsh7.6 /usr/bin/tclsh
ln -sf /usr/local/bin/wish4.2 /usr/bin/wish
Entrate poi nel file /etc/profile o nel file ~/.profile e scrivete:
export TCL_LIBRARY=/usr/local/lib
export TK_LIBRARY=/usr/local/lib
Questi comandi regolano le variabili d'ambiente.
FINE DELL'INSTALLAZIONE...
2. Regole
Poche ma ferree.
- Incominciamo col dire che in Linux non ci sono estensioni particolari per il file script, ma se poi vorremmo utilizzare questo programma per internet è necessario che questo venga usato con l'estensione .tcl . Non è necessario ma è meglio.
- Il programma non parte se prima non lo si rende eseguibile attraverso il comando: chmod +x nome_file.tcl
- Io parto dal presupposto che i file necessari (cioè l'interprete dei comandi tclsh) sia contenuto nella directory /usr/bin/
- "parole varie" Le virgolette servono per far considerare più parole come una sola. Questo è necessario per i testi o simili.
- Il segno $ e tutte le sue funzioni viene considerato solo se tra parentesi quadrate. ESEMPIO: [$i + 34] Poi vedremo che non ha senso, ma soltanto dopo...
- Le parentesi graffe {} si usano prevalentemente per le procedure.
- \ si usa per caratteri speciali (come le " che si per renderle visibili bisogna fare \". Li vedremo più avanti), ma anche per andare a capo e simili (\n e \r come in C).
- I commenti si fanno grazie al segno #
Tutto quello che ora faremo sarà senza grafica in ambiente X. La grafica sarà l'ultima cosa che impareremo a fare. Altrimenti vi manca il bagaglio culturale. E la cultura è potere! Comunque rilassatevi, io questo programma l'ho imparato in circa una settimana. Voi ci impiegherete circa un mesetto, ma non vi preoccupate!
3. Scrivere, commentare, ecc...
Incominciamo subito con un esempio:
-----INIZIO---------
#!/usr/bin/tclsh
#Questo è un commento, quello sopra \
no. E un comando necessario e intoccabile. \
Come vedete queste ultime righe non sono \
precedute dal solito segno di commento perché \
grazie al segno che c'è in fondo ad ogni riga \
cioè questo: \
io posso continuare a fare commenti.
puts "Ciao mondo"
#Con questo comando scrivo Ciao Mondo sullo schermo \
avrei potuto però anche fare:
puts stdout {Ciao mondo}
#Questo comando è uguale a prima.
------FINE-----------
Per non avere il ritorno a capo basta usare l'opzione -nonewline, usato così:
puts -nonewline "Ciao Mamma"
In questo modo non si andrà a capo.
4. Variabili e simili
Con il TCL (che è il programma che impareremo per primo...) non ha bisogno, al contrario di molti altri programmi, di inizializzare le variabili all'inizio del programma. Le variabili che si usano di più sono quelle SCALARI. Queste si usano perché non occupano memoria e, appunto, non hanno bisogno di dichiarazioni iniziali. Per creare una variabile bisogna usare il comando set.
-----INIZIO---------
#!/usr/bin/tclsh
set nome giovanni
puts "Il nome di questo programma e\' $nome"
-----FINE-----------
Come potete vedere questo è un programmino che usa la variabile nome per inserire al suo interno la parola giovanni e poi la stampa. La variabile viene stampata grazie al comando puts e il $ prima della variabile. Ho usato anche il comando \' per fare l'apostrofo, perché questo è uno dei comandi che devono essere preceduti da \.
Per fare calcoli bisogna usare il comando expr contenuto tra le parentesi quadrate.
esempio:
set a 5; set b 2
set c [expr 5/2]
puts $c
set d $c
puts [expr 5.0/2]
unset d
Ho fatto un po' di roba inutile! Guardiamo bene:
La prima riga è normale, ho semplicemente fatto due righe in una mettendo un ; tra un comando è l'altro. E' infatti uguale:
set a 5
set b 2
e
set a 5; set b 2
Nella seconda ho creato la variabile c contenente la frazione 5/2. Come vedete expr deve essere contenuto tra parentesi quadrate. Nella terza stampo la variabile $c (vedrete poi che stampa soltanto 2 come risultato, per ovviare a questo avrei dovuto mettere al posto che [expr 5/2] il comando [expr 5.0/2]). Non ho messo le "" perché è una parola sola. Nella quarta riga ho creato la variabile d contenente il valore di c. Nella quinta è stampato la frazione 5/2 ma stavolta ho messo 5.0/2 in modo che mi facesse vedere anche i numeri dopo la virgola. Nell'ultima riga ho eliminato la variabile d.
Esiste anche un altro modo per impostare la virgola e in numeri dopo. Questo è ottenibile grazie a questo comando:
set tcl_precision n
ove n sta per il numero di valori che deve inserire dopo la virgola.
Quindi nell'esempio:
set tcl_precision 9
puts [expr 1/3]
il risultato sarà 0.333333333 quindi 9 numeri dopo la virgola.
Gli array fanno parte delle variabili e quindi li inserisco qui.
Per creare array si usa il seguente metodo:
set variabile(nome_prima) ciao
set variabile(nome_seconda) addio
set variabile(nome_terza) "come stai?"
Come vedete ho creato un array di variabili di nome variabile e come "sottotitolo", nome_prima, nome_seconda e nome_terza.
Quindi ricapitolando gli array sono variabili che possono contenere più dati all'interno di una stessa variabile. Questo lo fa. Infatti all'interno della variabile variabile c'è ciao, addio e come stai?.
Per richiamare queste basta usare il comando:
puts $variabile(nome_prima)
puts "ed ecco a voi un altro metodo: $variabile(nome_seconda)"
La differenza tra il primo comando e il secondo è che il primo funziona con una sola parola e quindi non si mettono le virgolette. Nel secondo caso ho messo le virgolette perché ho inserito il testo.
Per sapere quante variabili può contenere l'array in questione si usa il comando:
puts [array size variabile]
ove array e size sono fissi e variabile è il nome dell'array che ci interessa. La risposta a questo comando sarà 3, poichè l'array variabile si divide in 3.
Ora parlerò di liste. Le liste sono variabili che contengono determinati valori e che io posso leggere e modificare lungo il programma. Il comando per far ciò è:
set nome_lista {1 2 3 4 5 6}
Crea una lista di nome nome_lista e contenente i valori 1,2,3,4,5,6. Posso creare però anche una lista contenente gruppi di valori:
set nome_lista {{1 2 3}{4 5}{6}}
Come vedete ho creato una lista contenente come valore più blocchi di dati.
I comandi per leggere questi dati sono:
I comandi per leggere e modificare sono:
-----------------------------------------------------------------------
| llenght nome_lista | Mi da il numero di dati inseriti nella lista |
-----------------------------------------------------------------------
| lindex lista indice | Mi da il valore di numero della lista |
| | L'indice può essere un numero da 0 in avanti |
-----------------------------------------------------------------------
| linsert lista indice elemento |Inserisce l'elemento nella lista |
-----------------------------------------------------------------------
| lsort opzioni lista | Ordina una lista in base alle opzioni: |
| | - ascii | logica lessicografica |
| | - integer | in base al numero ascii |
| | | crescente |
| | - increasing | in ordine crescente |
| | - decreasing | in ordine decrescente |
-----------------------------------------------------------------------
Ovviamente per visualizzare qualcosa bisogna usare questo metodo:
puts [lsort -decreasing nome_lista]
cioè usando il comando puts.
Per ricevere un valore, una risposta che deve essere inserita ovviamente all'interno di una variabile si usa il seguente comando:
set a [gets stdin]
Con questo comando, il programma aspetta che l'utente inserisca un valore. E' semplice il concetto: creo una variabile (nel mio caso di nome a) e al posto di inserire un valore imposto che questo sia preso dalla tastiera (gets stdin che è un comando fisso).
Per avere un valore da un utente io posso usare anche la formula:
puts "Dammi un valore: "
gets stdin ciao
Avrò così la variabile ciao contenente il valore.
Mediamente si usa per il comando puts l'opzione -nonewline perché altrimenti si va a capo nella richiesta di valore.
5. Stringhe e simili
Per il linguaggio tcl tutto è stringa pure un numero. I numeri diventano tali solo quando sono preceduti dal comando expr che permette di calcolare. Per gestire le stringe esiste un comando particolare che è:
string opzione argomento
ove opzione ve lo spiego fra un po', e argomento è la stinga in questione.
Le opzioni più comuni sono compare, length, match e trim.
Ma più esattamente queste opzioni sono:
-----------------------------------------------------------------------
| string compare | Confronta due stringe e da la diversità in |
| |ordire alfabetico: |
| | -1 se è minore la prima, 0 se sono pari |
| | 1 se la prima è maggiore |
-----------------------------------------------------------------------
| string length | Da il numero di caratteri |
-----------------------------------------------------------------------
| string match | Confronta con un modello la stringa. I valori |
| | di confronto sono uguali a quelli di compare. |
| | Il modello può essere tra questi: |
| | abc* | confronta tutti i caratteri con tutti |
| | abc? | confronta un singolo carattere |
| | \ | per confrontare i caratteri * e ? |
-----------------------------------------------------------------------
| string strim | restituisce la string senza i caratteri |
| | specificati. Se non metto niente mi toglie |
| | gli spazi bianchi, i punti, le tab, ecc... |
-----------------------------------------------------------------------
Un altro esempio inutile:
------INIZIO--------------
#!/usr/bin/tclsh
string compare "abcdefgh" "ilm"
#il risultato sarà -1 perché \
ilm sono lettere dopo abcdefgh
string compare "abcd" "abcd"
#il risultato sarà 0
string compare "def" "abc"
#il risultato sarà 1
puts [string trim "ciao mamma " .m]
#il risultato sarà ciaoaa perché ho \
tolto tutti gli spazi e i punti e e le m.
#in vi ho spiegato i cicli ma sono semplici questi:
set ciao "mamma mia"
if {[string length $ciao]>5} {
puts "Nome lungo"
} else {
puts "Nome corto"
}
#nel nostro caso scrive nome lungo.
--------FINE--------------
Dovete fare incredibilmente attenzione con gli spazi nel ciclo, altrimenti vi darà errori vari. Già! Gli errori sarà un argomento che dovrò trattare.
Il comando split serve per sostituire caratteri separatori all'intero di una stringa:
split stinga caratteri
puts [split "ciao mondo"]
risultato sarà: ciao mondo
se invece scrivo
puts [split ciao*mondo *]
risultato sarà: ciao mondo
6. Cicli
Come ogni programma ci sono i cicli. I primi due sono l'IF e il SWITCH.
Incominciamo col primo, l'IF.
Il funzionamento del comando IF è sempre lo stesso di ogni altro linguaggio di programmazione. Ma è particolarmente importante qui i numeri di spazi e l'impostazione grafica. Altrimenti non funge!
IF {condizione1} {
corpo1
}
Come potete vedere le parentesi graffe contengono il corpo e la condizione. La condizione può essere del tipo: {$a>2}, e qualsiasi altro tipo, ma l'importante è che non compaiono spazi tra i vari fattori. E' errore: {$a > 2}. Non devono comparire spazi!
Tra la parentesi di chiusura della condizione e la prima del corpo ci deve essere uno spazio, altrimenti errore! Insomma deve essere fatta come nell'esempio qui sotto:
--------INIZIO-------------
#!/usr/bin/tclsh
puts "il valore di A e\': "
set a [gets stdin]
puts "Il valore di B e\': "
set b [gets stdin]
if {$a==$b} {
puts "A e B sono uguali"
} elseif {$a>$b} {
puts "A e\' maggiore di B"
} else {
puts "A e\' minore di B"
}
--------FINE---------------
Spiegazione: il comando set a [gets stdin] permette di ricevere un valore (ve lo ricordate?). Poi attraverso un ciclo IF confronto (==) i valori di a e b (ricordo che a e b sono le variabili mentre $a e $b sono i valori dentro le variabili). Poi se sono uguali dico... mentre se sono diversi dico ...
Da notare i comandi elseif e else. La differenza è che elseif apre già un ciclo if partendo da presupposto che il primo non si sia avverato. Else invece non apre nessun ciclo.
Esiste poi il ciclo con switch che permette il confronto booleano fra due stringhe o due proposizioni o di una stringa e un modello.
Si usa così:
switch opzioni stringa modello corpo
oppure
switch opzioni stringa {modello corpo}
Le opzioni possono essere :
-------------------------------------------------------------------------------
| -exact | confronta e da esito positivo solo se la stringa e il modello |
| | sono uguali |
-------------------------------------------------------------------------------
| -glob | si usa in concomitanza con il comando string match che crea |
| | un modello da confrontare poi con la stringa in questione |
-------------------------------------------------------------------------------
| -regex | permette l'uso delle espressioni regolari (ve le spiego...) |
-------------------------------------------------------------------------------
| -- | indica la fine delle opzioni |
-------------------------------------------------------------------------------
Esempio chiarificatore:
---------INIZIO--------------
#!/usr/bin/tclsh
puts "Dammi un valore booleano: "
gets stdin booleano
switch -exact -- $booleano {
1 {puts vero}
yes {puts vero}
true {puts vero}
sì {puts vero}
vero {puts vero}
0 {puts falso}
no {puts falso}
false {puts falso}
falso {puts falso}
default {puts "Valore inserito non booleano"}
}
---------FINE----------------
Spiegazione: ho chiesto un valore se il primo valore è uguale alle parole 1, yes, true, sì o vero allora verrà visualizzata la parola vero. Al contrario se inserisco le parole 0, no falso, false verrà stampato la parola falso.
Se inserisco un altro valore verrà visualizzato la frase Valore inserito non booleano.
Da notare il comando default che permette di scrivere qualcosa, o di fare una determinata operazione, se tutti gli altri confronti falliscono.
Gli altri ciclo sono il FOR, il WHILE e il FOREACH. Incominciamo con il FOR.
La struttura è così:
for {inizializzazione_variabile} {condizione} {incremento} {
...operazioni varie...
}
ESEMPIO:
for {set a 0} {$a<=10} {incr a} {
puts "A vale $a"
}
Questo ciclo stamperà questo:
A vale 0
A vale 1
A vale 2
A vale 3
A vale 4
A vale 5
A vale 6
A vale 7
A vale 8
A vale 9
A vale 10
E la spiegazione è questa:
for apre il ciclo
{set a 0} crea una variabile a di valore 0
{$a<=10} Imposta che non deve superare il valore di 10
{incr a} La incrementa
{ apre in corpo di operazioni
puts "A vale $a" scrive il valore di $a
} chiude il tutto
Cìò si poteva fare anche un ciclo WHILE:
while {condizione} {
...operazioni varie...
}
Che nel nostro caso diventerebbe:
set a 0
while {$a<=10} {
puts "Il valore di A è $a"
incr a
}
Abbiamo appena visto il funzionamento di WHILE. Fate attenzione a un comando in particolare cioè incr a. Questo comando incrementa la variabile a. Se non l'avessi messo si sarebbe originato un ciclo, all'infinito.
Ora è il momento di FOREACH che si usa prevalentemente con le liste:
foreach variabile lista {
...operazioni varie....
}
foreach a {1 2 3 4 5 6 7 8 9 10} {
puts "Il valore di A è $a"
}
Il funzionamento è uguale agli altri due. Qui indico i valori che a deve toccare e poi gli faccio fare una operazione tante volte quante sono i valori nella lista.
7. Procedure
Anche TCL può essere strutturato in procedure. Ciò comporta che può avere dei blocchi di codice (appunto chiamati procedure) che possono essere richiamati attraverso il comando specifico. L'utilità di ciò (lo dico per chi non le ha mai utilizzate) è di alleggerire il corpo del programma, di racchiudere parti che verrebbero fatte funzionare più volte una volta per tutte senza riscriverle sempre, e in più di trovare velocemente gli errori.
nome_procedura {} {
...comandi vari....
}
Tutto ciò si fa grazie al comando proc seguito dal nome della procedura. Se volessimo che la procedura prendesse variabili già usate e riempite dal programma per effettuare determinate operazioni, questo di deve fare nel seguente modo:
set a 5
set b 4
proc somma1 {} {
set a 1
set b 9
set somma [expr $a+$b]
puts $somma
}
proc somma2 {} {
global a b
set somma [expr $a+$b]
puts $somma
}
proc somma3 {a b} {
set somma [expr $a+$b]
puts $somma
}
somma1; #risultato 10
somma2; #risultato 9
somma3; #risultato 9
Vediamo un po' cosa fa questo semplice programmino: creo due variabili a e b.
- PRIMA PROCEDURA: somma 2 variabili che si crea lui e che non centrano nulla con le variabili a e b del programma generale. Il risultato sarà 10.
- SECONDA PROCEDURA: somma le due variabili del programma generale poichè riprese dal comando GLOBAL. Questo comando permette di riprendere le variabili dal programma e di utilizzarle.
- TERZA PROCEDURA: prende le due variabili e le somma grazie all'inserzione di esse tra le parentesi graffe.
Vediamo il comando arg:
proc ciao {a b c arg} {
puts $a
puts $b
puts $c
puts $arg
}
prova 1 2 3 4 5 6 7 8
Il risultato sarà:
1
2
3
4 5 6 7 8
Questo perché il comando arg stampa tutti i valori dopo quelli che la procedura può accettare considerandoli un unico valore. Nel nostro caso la procedura ciao poteva ricevere 1 2 3 rispettivamente dalle variabili a b c il resto no. Quindi arg accetta il resto ma lo considera unico, quindi sulla stessa riga.
Per modificare un valore di una variabile attraverso una procedura si usa il comando upvar usato nel seguente modo:
set a 5
proc ciao {} {
upvar a b
set b 9
}
ciao
puts $a; #
apparirà 9
Questo perché alla riga 6 ho fatto partire la procedura ciao che cambiava a da 5 a 9.
8. File
Per aprire un file bisogna usare queste righe di comando:
set idfile [open "./prova.doc" r]
while {[gets $idfile riga] !=-1} {
puts $riga
}
close $idfile
Che spiegati sono: creo una variabile di nome idfile ove apro (open) un file di nome "prova.doc" in sola lettura (r).
Dopo di che faccio incominciare un ciclo (while) finchè il file non finisce. Poi stampo ogni singola riga.
Ricordarsi sempre di chiudere il file altrimenti questo non verrà salvato con le modifiche che voi avete fatto (close $idfile)!
Questo è la spiegazione. Quindi abbiamo capito che il comando open si utilizza così:
open "nome file" modo_di_lettura
Il modo di lettura può essere r (read quindi solo lettura), ma anche w (write) nel seguente esempio ove creo un file di nome prova.txt:
set idfile [open "./prova.txt" w]
puts $idfile "CIAO MAMMA!!!"
close $idfile
Queste due righe aprono un file di nome prova.txt in scrittura e poi ci scrivono sopra CIAO MAMMA!!!
Ovviamente possiamo aprire i file anche in binario:
set idfile [open "./prova" r]
while {![eof $idfile]} {
set buffer [read $idfile 1024]
...comandi e comandi...
}
close $idfile
Altro importantissimo comando è il GLOB che permette di trovare i file con caratteristiche comuni e di fare operazioni su tutti quanti in contemporanea:
foreach txt [glob *.txt] {
set idfile [open $txt r]
while {[gets $idfile riga] !=-1} {
puts $riga
}
close $idfile
}
Questo caso permette di trovare tutti i file con estensione .txt e di visualizzarli.
9. Eseguire comandi
Per eseguire comandi del prompt e non, bisogna usare in comando exec:
exec ls
Ma se volessimo visualizzare tutti i file *.txt (cioè tutti quei file che hanno come estensione txt: MA SE NON SAPETE QUESTO CHE RAZZA DI PROGRAMMATORI SIETE...) non potete vare così:
exec ls *.txt; #errore!!!!
Per risolvere questo problema si usano i comandi eval e glob:
eval exec ls [glob *.txt]; #esatto!!!
Questo comando permette di visualizzare i file *.txt.
EX CLARO?
10. GRAFICA!!!
Incominciamo ora, dopo aver capito il base del TCL, con i comandi base del TK.
Questo linguaggio è molto semplice, leggero e grafico, e ha una struttura fissa per tutti i comandi:
nome_dello_strumento nome_nostro opzioni
Il nome_dello_strumento può essere button (pulsante), label (etichetta), ed altri.
Il nome_nostro è il nome che vogliamo dare al nostro pulsante o etichetta, mentre le opzioni sono cosa farà questa etichetta o in generale, strumento.
Incominciamo quindi subito con l'impostare le dimensioni della finestra e i suoi colori:
-------INIZIO---------
#!/usr/bin/wish
wm title . "CIAO MAMMA!!"
wm resizable . 0 0
. configure -bg white
-------FINE-----------
Spiegazione:
La prima riga come vedete imposta un altro interprete dei comandi che permette di visualizzare in grafica.
wm imposta le caratteristiche della pagina e, nella seconda riga in particolare imposta il titolo della finestra principale "." con il nome di CIAO MAMMA!!
Come, finestra principale? Sì, perché la finestra principale è chiamata "." mentre i suoi oggetti sono .ciao .nome_a_caso che dovremmo poi impostare noi. Quindi . è il principale mentre gli oggetti contenuti (che possono essere pulsanti, etichette o simili) si chiamano .nome . Diverso è con i frame poichè questi saranno anch'essi oggetti e quindi detti: .nome_frame ma dato che essi possono reggere pulsanti, etichetti, ecc i nomi di questi ultimi saranno .nome_frame.nome_pulsante .
Capito?
Ve lo spiego con un grafico:
.
/\
/ \
/ \
.pulsante .frame
|
|
/ \
/ \
/ \
.frame.pulsante \
.frame.frame2
|
|
|
.frame.frame2.pulsante
Ex claro?
Continuando con la spiegazione:
wm resizable . 0 0 serve ad impostare che le dimensioni della finestra . non possono essere modificate nÈ in altezza (primo 0) nÈ in larghezza (secondo 0).
. configure -bg white
Configuro che lo sfondo (-bg) della finestra principale (.) deve essere bianco.
Vi consiglio di farvi uno schizzo su carta delle vostre costruzioni altrimenti ... La vedo tesa sul fatto di riuscire a disegnare bene i vostri programmi!
Vi ricordo che per visualizzare i comandi che mettete dovrete usare il comando pack che però spiegherò dopo gli altri. Quindi per ora aspettate ... e leggete!
Etichette
Incominciamo con un esempio:
label .nome -text "Ciao!! Come stai?" -bg red
Per fare le etichette si usa il comando label seguito dal nome dell'etichetta e dal comando text che regola il testo. Dopo di che bisogna regolare il colore dello sfondo. Se non facciamo questo ultimo comando apparirà quello default. Che nel nostro caso è bianco (vedi sopra).
Frame
I frame si fanno attraverso il comando FRAME:
frame .nome_frame -bg colore
I frame dividono la finestra in più parti. Per mettere nel nostro frame una etichetta dovremmo fare così:
frame .nome_finestra.nome .text "Etichetta nel frame!!"
Input
Gli input si creano con il comando Entry:
entry .ciao -textvariable a
Si crea un input cioè quello spazio dove posso scrivere qualcosa, con il nome .ciao.
Ciò che scriverò andrà inserito nella variabile a.
L'uso delle variabili lo do per noto poichè è lo stesso principio di tcl.
Quindi non badando alla grafica:
-------INIZIO---------
#!/usr/bin/wash
wm title . "CIAO MAMMA!!"
wm resizable . 0 0
. configure -bg white
label .1 -text "Dammi il primo numero: "
entry .2 -textvariable a
label .3 -text "Dammi il secondo numero: "
entry .4 -textvariable b
pack .1 .2 .3 .4
set c [expr $a+$b]
label .5 -text "La somma è $c"
pack .5
-------FINE-----------
Non vi chiedete il funzionamento pack perché ve lo spiegherò dopo. Per ora vorrei farvi notare che le etichette sono 2 e che gli input sono anch'essi 2. Poi sommo le variabili allo stesso modo in cui facevo con TCL e poi visualizzo.
Pulsanti
I pulsanti si fanno così:
button .nome -text "Il testo sopra il pulsante" -command {opzione}
Il pulsante di nome .nome e con il testo "Il testo sopra il pulsante se cliccato con il mouse farà partire il comando opzione.
Tra le opzioni ci sono in prevalenza 2:
- exit che comporta l'uscita dal programma
- una procedura (le strutture delle procedure le do per note dal TCL"
Esiste, sempre legato ai pulsanti i RADIOBUTTON che sono i pulsantini a rompo.
Si usano come gli altri, solo che non si mette il testo dentro ma fuori e si fa così:
radiobutton .nome -text "Ciò che si vuole."
Disegnare
Per disegnare si usa il comando canvas.
canvas .nome -width numero -height numero -bg colore
ove nome è il nome della parte dedicata al disegno, -width regola l'altezza in pixel della larghezza e height della altezza. Il colore è il colore di sfondo che già conosciamo.
canvas .ciao -width 200 -hieght 200 -bg black
Vi ricordo che non disegnare voi con il mouse ma visualizza l'andatura di un grafico o simili.
Per cancellare un grafico e scrivere sopra basta fare
.ciao delete all
Cancellerà tutto sul grafico.
PACK
Il pack permette di visualizzare gli oggetti nel programma. Ne ho parlato per ultimo perché ha 200 milioni di opzioni.
Cos'è il PACK? Non è proprio un visualizzatore è un gestore. Cioè è un "programma" che riempie automaticamente le opzioni che noi lasciamo vuote o trascuriamo (quando ci dimentichiamo di mettere il colore di sfondo o ecc..), e si preoccupa di posizionare correttamente gli oggetti nella grafica.
Esistono 2 gestori. Il placer e il packer. Io uso il secondo prevalentemente perché è più completo e permette operazioni che l'altro non permette. Comunque ve li spiego entrambi.
IL PLACER colloca gli oggetti relativamente al contenitore e in modo separato.
Quindi provoca la sovrapposizione di oggetti o simili.
Il funzionamento è questo:
place .nome_oggetto -x n -y n
Ove n sono i due numeri che riguardano le ordinate e le ascisse.
Si può usare il comando -anchor per ancorare l'oggetto al bordo:
place .nome -anchor center
Il PACKER
Permette di gestire più oggetti in contemporanea. Il suo funzionamento "intelligente" è questo:
- Sceglie il lato della cavità (posto in cui l'oggetto può essere inserito)
- Ricava una sezione per l'oggetto (maggiore o no dell'oggetto stesso)
- Può ingrandire l'oggetto se vogliamo
- Lo colloca.
Questa è la differenza tra il Packer e il placer, cioè valuta la distanza tra oggetto e oggetto prima di collocare.
Ora beccatevi questa tabellina:
-------------------------------------------------------------------------------
| BORDATURE |
-------------------------------------------------------------------------------
| -padx 2m -pady 1m | Regola la distanza di 2 rispetto ai bordi o ad un |
| | altro oggetto. Padx lateralmente, pady verticalmente |
-------------------------------------------------------------------------------
| -ipadx 2m -ipady 1m | Regola la distanza di 2 rispetto ai bordi o ad un |
| | altro oggetto ma a differenza di quello sopra, allarga|
| | i bordi. |
-------------------------------------------------------------------------------
| -padx 2m -pady 1m \ | Fa per metà il primo comando e per metà l'altro |
| -ipadx 2m -ipady 1m | |
-------------------------------------------------------------------------------
Ora una per le Saturazioni (cioè l'espansione dei pulsanti):
-------------------------------------------------------------------------------
| SATURAZIONI |
-------------------------------------------------------------------------------
| -pack .1 .2 -side top | Mette un oggetto sotto l'altro |
-------------------------------------------------------------------------------
| -pack .1 .2 -side left| Mette un oggetto a sinistra l'altro |
-------------------------------------------------------------------------------
| -pack .1 .2 -side \ | Mette un oggetto a destra l'altro |
| right | |
-------------------------------------------------------------------------------
| -pack .1 .2 -side top\| Fa quello sopra e in più estende i bordi fino al |
| -fill x | consentito dai bordi in orizzontale |
-------------------------------------------------------------------------------
| -pack .1 .2 -side top\| Fa quello sopra e in più estende i bordi fino al |
| -fill y | consentito dai bordi in verticale |
-------------------------------------------------------------------------------
| -pack .1 .2 -side top\| Ovviamente entrambi |
| -fill y -fill x | |
-------------------------------------------------------------------------------
PS .1 e .2 sono due oggetti a casi. \ Indica (come in TCL) il continuamento dello stesso codice anche se a capo.
Ora un'altra per le Espansioni. Cosa sono le espansioni? Sono l'allargamento della finestra da una parte:
-------------------------------------------------------------------------------
| ESPANSIONI |
-------------------------------------------------------------------------------
| -pack .1 .2 -side left | Lo conosciamo già. Sarà il nostro punto di partenza |
-------------------------------------------------------------------------------
| -pack .1 .2 -side left | Aggiungo al comando di prima un altro pack che regola|
| -pack .3 -side left \ | la visualizzazione del .3 . Poi espando. |
| -expand true | |
-------------------------------------------------------------------------------
| -pack .1 .2 -side left | Uguale a prima solo che aumento la larghezza di x |
| -pack .3 -side left \ | nella parte prima espansa. |
| -expand true -fill x | |
-------------------------------------------------------------------------------
| -pack .1 .2 -side left\| Se espando due comandi questi si mettono in modo |
| -expand true | equidistante l'un l'altro |
-------------------------------------------------------------------------------
| -pack .1 .2 -side left\| Uguale a prima solo che ora saturo i bordi |
| -expand true - fill \ | |
| both | |
-------------------------------------------------------------------------------
Ex claro? Provate e capirete meglio!
Ora dovreste capire il semplicissimo programma, neanche tanto curato Euro v1.0:
--------INIZIO-----------
#!/usr/bin/wish
wm title . "Euro v1.0"
wm resizable . 0 0
. configure -bg white
label .titolo -text "Convertitore" -bg white
label .titolo1 -text "EURO-LIRE" -bg red
pack .titolo .titolo1
set a 0
set b 0
label .titolo2 -text "Euro: " -bg white
entry .euro -textvariable a
label .lire -text "Lire: $b" -bg white
pack .titolo2
pack .euro -side top
pack .lire -pady 10
button .b1 -text Converti -command {euro-lire}
button .esci -text Esci -command {exit}
pack .b1 .esci -side left -pady 10
proc euro-lire {} {
global a
set b [expr $a*1936.27]
.lire configure -text "Lire: $b"
pack .lire
}
-------FINE--------------
Provate a fare l'inverso, da Lire a Euro...
Listbox
Le listbox mediamente si fanno in un frame poiché così compaiono come oggetto unico.
I comandi comunque sono 2:
listbox .nome opzioni
scrollbar .nome opzioni
Esempio:
frame .frame
scrollbar .frame.scroll -command ".frame.list yview"
listbox .frame.list -yscroll ".frame.scroll set" -width 20 -height 16 -setgrid 1
Che vuol dire:
Creo un frame di nome .frame. Faccio una barra di scorrimento di nome .frame.scroll e che mi permette di muovere attraverso la lista di .frame.list in verticale (yview).
Poi creo una lista di nome .frame.list verticale (-yscroll) legata alla barra di prima (.frame.scroll set) di larghezza 20 e altezza 16. Setgrid imposta la larghezza tra una linea e l'altra.
Eventi
Gli eventi sono creati grazie al comando bind. Gli eventi sono legati in prevalenza al mouse e ai suoi click. Si può quindi considerare il pulsante un evento.
Vediamo l'esempio:
--------INIZIO-------------
#!/usr/bin/wish
frame .f -width 100 -height 100
bind .f <Button-1> {puts "Button 1 premuto"}
bind .f <Button-2> {puts "Button 2 premuto"}
bind .f <ButtonRelease-1> {puts "Button 1 rilasciato"}
bind .f <Double-Button-1> {puts "Doppio click Button 1"}
bind .f <Any-Motion> {puts "Posizione $x, $y"}
pack .f
-------FINE------------
Nel seguente programma possiamo vedere come creato un frame di nome .frame collego ad un click sul frame la scritta Button 1 premuto, ecc...
Quindi possiamo osservare che gli eventi possibili sono:
<Button-1> Cioè Pressione del pulsante 1 del mouse
<Button-2> Cioè Pressione del pulsante 2 del mouse
<Button-3> Cioè Pressione del pulsante 3 del mouse
<ButtonRelease-1> Rilasciamento del pulsante 1
<ButtonRelease-2> Rilasciamento del pulsante 2
<ButtonRelease-3> Rilasciamento del pulsante 3
<Double-Button-1> Doppio Click
<Any-Motion> Cioè indica nella variabili $x e $y la posizione del mouse.
11. Cose carine
Il comando FOCUS .nome_di_qualcosa_già_esistenzapermette di selezionarlo e, al passaggio del mouse di colorarlo.
ES:
button .ciao -text ciao
focus .ciao
pack .ciao
I mille wm:
wm title . "nome finestra"; # GIA VISTO!
wm geometry . 200x200; #dimensioni della finestra
wm iconify . ; #iconifica la finestra
destroy .x Distrugge la finestra
Catturare il mouse:
grab .x
grab release .x
Ove x è il nome della finestra in questione.
showVars Mostra le variabili in continuo aggiornamento
Creare finestre di dialogo. Quelle che ti dicono: Attenzione...
mkdialog .nome "Attenzione..." $msg warning "Ok "Annulla" "Cancella"
Poi le opzioni si modificano in base al $msg.
Esistono ancora in questo argomenti i tk_messageBox che vanno usati così:
tk_messageBox -icon error\
-type ok \
-message "Attenzione...."
return 1
Ove icon indica quella di errore (è predefinita), type indica il pulsante e message indica il messaggio da inserire.
Menu
Per creare menu possono essere creati attraverso il comando menubutton.
menubutton .ciao -text "File" -menu .ciao.1 -bd 3 -relief raise
menu .ciao.1
ove -text indica il testo del menu, -menu indica il menu contenente tutte le opzioni, -bd indica il bordo e -relief indica il tipo di bordo (cioè in rilievo).
Il secondo comando indica un menu a tendina.
Qui dentro posso inserire cioè che voglio, dalle etichette a dei pulsanti:
.ciao.1 add opzione funzioni
pack .ciao
Le opzioni in questione sono:
cascade Crea i menu che poi si aprono in sotto menu
radio Crea i menu con un pallino
checkbutton Crea i menu con un rettangolino
command Crea il classico pulsante nel menu
radiobutton Crea un rombo
separation Crea una separazione
Le funzioni possono essere:
- label "ciao" Che vuol dire il nome del pulsante sarà ciao
- command {} Indica che tra le parentesi ci sarà un comando o una procedura che partirà
ES:
---INIZIO---------
#!/usr/bin/wish
label .a -text CIAO!!
menubutton .ciao -text "File" -menu .ciao.a -bd 3 -relief raise
menu .ciao.a
.ciao.a add command -label "Esci1" -command {exit}
.ciao.a add separator
.ciao.a add radio -label "Esci2" -command {exit}
pack .ciao
-------FINE-----------
Le scale di graduazione sono tipo le levette degli HI-FI. Si fanno così:
scale .ciao -orient horizontal -length 100 -from 0 -to 1 -tickinterval 0.5 \
-variable t -resolution 0.1
Che vuol dire: Creo una scala di nome .ciao in orizzontale (orient horizontal, ma poteva esser anche verticale (orient vertical), che va (from) da 0 a 1 -Fai che il cursore si trovi inizialmente (tickinterval) a 0.5, che la posizione definitiva sia insita nella variabile t e che la scala di risoluzione (resolution) sia di 0.1.
Chiaro?
12. TCL/TK e Internet
Avete creato un bel programmino e volte visualizzarlo su internet. Potete farlo grazie ai programmi browser più famosi Netscape e Internet Explorer. Dovete scaricarvi le sorgenti e gli eseguibili di un programma chiamato plugin scaricabile all'indirizzo:
http://sunscript.sun.com/plugin/download.html
Qui potete scaricarvi questo programma. Ovviamente per ragioni di sicurezza (cazzo!) hanno tolto i seguenti comandi:
cd, exec, fconfigure, file, glob, pwd, socket, bell, clopboard, grab, menu, send, tk, toplevel, wm.
Non vi preoccupate se non li conoscete. Questi hanno funzioni particolari che, magari, prima o poi vi spiegherò in un corso avanzato di questo programma.
Si possono ripristinare questi comandi andando a ritoccare il file plugin.tcl contenuto nella directory:
- per Linux: ~/.netscape/tclplug/2.0/config
- per Windows: \config nella directory d'installazione.
*******************************
Ma, non vi preoccupate: è da un po' che sto cercando di programmare un eseguibile attraverso Web capace di modificare questo file per poi giocare con il computer della vittima.... (ovviamente quello che qui ho detto non è affatto vero, io non vorrei mai intaccare un computer non mio, ecc...)
*******************************
Comunque mediamente questo programma non è installato automaticamente. Quindi...
Se avete voglia di scaricarvelo, le righe di HTML per far partire il file (di nome prova.tcl) è questo:
<HTTML>
<HEAD>
<TITLE>Programma di prova!!</TITLE>
</HEAD>
<BODY>
<EMBED SRC="prova.tcl" WIDTH="300" HEIGHT="300">
</BODY>
</HTML>
Se non sapete cosa questo sia, leggetevi la mia guida sull'HTML sempre su questo sito!
Ovviamente vi ricordo che la larghezza della pagina deve essere quella del programma.
Questo file HTML deve essere salvato come nome_che_volete.html . Quindi visualizzatelo.
13. Creare un database
Lo sapete cos'è mSQL? mSQL è un programma per Linux che permette di creare database.
Questo programma poi si è sviluppato in più direzioni fino ad una versione compatibile con tcl. Questa permette di creare database al pari di ACCESS della Microsoft. Mica male! E' solo questione di pratica. Pensavo di inserire qui un mio programma di database per libri creato per schedare quelli di casa mia, ma dato che il programma è molto lungo ed esula dal "base" di questo programma, penso che lo spiegherò in un "avanzato".
Comunque sappiate che tcl è molto flessibile e permette di cooperare con molti altri linguaggi, arrivando a dei livelli incredibili.
-----------------FINE--------------------
Direi che con questo è tutto!
Per informazioni & C.
Michael Bakunin
bakunin@meganmail.com