2006-10-25

Tcl/Tk

tcl.jpg Faz mais de um mês que não escrevo nada sobre Informática! Como já faz tempo que quero escrever sobre Tcl/Tk, vamos lá!

Tcl (Tool Command Language) é uma linguagem de script de código aberto muito poderosa. Desenvolvido por John Ousterhout, é costume dizer que é uma linguagem fácil, mas discordo.

É baseada em comandos (há uma variante orientada a objetos, chamada [incr Tcl]) com uma proposta interessante: tudo são strings!

Uma string em Tcl não precisa de delimitador, a menos que possua caracteres não-permitidos, como espaço e mudança de linha. Neste caso, o delimitador padrão é " (ou chaves).

Vamos a alguns exemplos...

Para se alterar ou ler o valor de uma variável usa-se o comando set. No exemplo a seguir, o script lê o valor da variável e retorna o dobro:

puts -nonewline stdout {Informe um número: }
gets stdin num
set num [expr [set num] * 2]
puts stdout "O dobro é [set num]"


O primeiro comando (puts) grava na saída padrão (stdout, a tela) a string «Informe um número: » sem mudar de linha (-nonewline). As chaves ({...}) também delimitam uma string, mas não interpretam colchetes (veja adiante).

Então o comando gets lê da entrada padrão (stdin, o teclado) um valor e atribui à variável num.

No próximo comando, set, usamos colchetes ([...]). Os colchetes interpretam um comando e são substituídos por seu retorno.

Ou seja, se foi atribuído o número 123 à variável num, no comando:
expr [set num] * 2


A parte entre colchetes, set num, retorna o valor de num, portanto 123, então os colchetes serão substituídos, recriando a string do comando assim:
expr 123 * 2


O comando expr avalia uma expressão matemática e retorna seu valor. Então:
set num [expr [set num] * 2]


Calcula o dobro do conteúdo de num e atribui a num.

O último comando grava na saída padrão (exibe na tela, ora pois!) a string «O dobro é [set num]», substituindo os colchetes pelo valor de num.

Repare que no primeiro puts, a string está protegida por chaves, e no segundo por aspas. Sempre dou preferência ao uso de chaves, mas as chaves protegem a string de interpretação, enquanto que aspas permitem a interpretação de colchetes (e cifrão, veja a seguir).

Agora, há um jeito de simplificar este código: seguindo as sintaxes de Shell e de Perl, existe uma forma simplificada de escrever set num com cifrão ($):
puts -nonewline stdout {Informe um número: }
gets stdin num
set num [expr $num * 2]
puts stdout "O dobro é $num"


Estruturas de controle


Dada a introdução, quero agora comentar algumas estruturas de controle de fluxo...

O primeiro comando é if. Sua estrutura é assim: if condição bloco1 [else bloco2]. Aqui, condição, bloco1 e bloco2 são strings (como não poderia deixar de ser). Então:
if {$sair == 1} {
puts stdout Tchau
exit
}


Se o conteúdo da variável sair for igual a um, exibe Tchau e sai. Como em outras linguagens, o bloco do else é executado se a condição for falsa.

A igualdade dupla (==) é usada para comparar valores numéricos. Para a comparação de strings, é usado o comando string com a opção equal:
if [string equal $var1 $var2] {
puts stdout {São iguais!}
} else {
puts stdout {São diferentes!}
}


Se quiser uma comparação ignorando maiúsculas e minúsculas, é só usar string equal -nocase. Repare que aqui a string interpretada pelo if como condição não é o comando em si, mas seu resultado.

Outro comando é o famigerado for.

A estrutura: for inicialização condição passo bloco. Novamente cada termo é uma string.

Vamos a um exemplo simples:
for {set i 0} {$i < 10} {incr i} {puts stdout $i}


Vai exibir todos os número de 0 a 9. Mas o comando é feio e difícil de guardar, né?

Então, existe um variante do Tcl chamado TclX (Tcl estendido), com um comando muito útil: loop.
loop i 0 10 {
echo $i
}


O comando echo de TclX é equivalente a puts stdout de Tcl. Em loop é possível passar mais um argumento entre o máximo e o bloco como passo (tipo: loop i 0 20 2 {...).

Obs.: TclX aceita todos os comandos de Tcl e implementa (estende) mais alguns.

Outros comandos de controle de fluxo interessantes em Tcl são: while, switch e foreach.

Funções


O comando para criar uma função é proc, que recebe como primeira string a lista de argumentos (separados por espaços) e como segunda string o bloco de comandos. Ex.:
proc fib n {
set a 0
set b 1
set c 1
while {$c <= $n} {
set aux $a
set a $b
incr b $aux
incr c
}
return $b
}


Então fib vai calcular a sequência de Fibonacci:

for {set i 0} {$i < 10} {incr i} {
puts stdout [fib $i]
}


Tk


Agora a parte mais interessante: Tk!

Tk é o toolkit gráfico de Tcl. O comando para usar Tcl com Tk é wish (e para usar TclX com Tk é wishx).

Em Tk a janela raiz é representada por um ponto (.).

Vamos criar um olá mundo!!!
#!/bin/sh
#\
exec wish "$0" "$@"

tk appname Ola
tk_setPalette gray

label .lbOla -text {Olá Mundo!!!}
button .btOk -text Ok -command exit

pack .lbOla .btOk


As três primeiras linhas são um cabeçalho pra podermos tornar o script executável.

O primeiro comando (tk appname) define o nome da aplicação (Ola), e o comando seguinte (tk_setPalette) diz pra usar como cores variantes de cinza (gray).

O comando label cria um rótulo (label) chamado lbOla na janela raiz (.) com o texto «Olá Mundo!!!». O comando button cria um botão chamado btOk na janela raiz (.) com o texto «Ok» e que, ao ser clicado (-command), executa exit (sair).

O comando pack indica que será usado o geometry manager pack. Geometry managers são gerenciadores de widgets (objetos gráficos) e geometria. Tk usa três: pack («empacota» em relação a posições esquerda, direita, em cima, em baixo, e tenta manter estas relações), grid (usa uma tabela – grade – colocando os widgets nas células da tabela) e place (desaconselhável: coloca os widgets em posições absolutas).

O gerenciador pack por padrão coloca os widgets a partir de cima (top), um de baixo do outro, centralizando (é possível mudar isso usando -side).

Para colocar os widgets um do lado do outro a partir da esquerda, usa-se -side left, a partir da direita: -side right. Para «amarrar» um widget em baixo, usa-se -side bottom.

O grid prende os widgets centralizados (é configurável) em células. A célula exata é informada através dos números de linha (-row) e coluna (-column). É possível que um widget ocupe mais de uma coluna (-columnspan) ou mais de uma linha (-rowspan).

O script acima poderia ser reescrito usando grid assim:
#!/bin/sh
#\
exec wish "$0" "$@"

tk appname Ola
tk_setPalette gray

label .lbOla -text {Olá Mundo!!!}
button .btOk -text Ok -command exit

grid .lbOla -row 0 -column 0
grid .btOk -row 1 -column 0


Para saber mais


O melhor lugar para se encontra mais informações sobre Tcl/Tk é na secção (n) (new) das manpages, mas um macete indispensável é digitar o seguinte comando no shell de um xterm:
tcl <<< tclhelp


[]'s

PS: Procure screenshots no Google!