14. A Linguagem Tcl/Tk

Tcl (pronuncia-se ticol, a abreviação de Tool Comand Language) é uma linguagem de script muito útil que roda na maioria das plataformas UNIX e Windows.

14.1. Widgets Tk

Combinada com a biblioteca gráfica Tk (pronuncia-se tikei), a qual fornece os Widgets (elementos gráficos), a Tcl pode ser usada para gerar programas com interfaces gráficas com o usuário.

Figura 73. Widget "label"

Widget "label"


Figura 74. Widget "entry"

Widget "entry"


Figura 75. Widget "checkbutton" e "button"

Widget "checkbutton" e "button"


A biblioteca Tk está para a Tcl assim como AWT e Swing está para o Java.

A biblioteca Tk não é exclusiva da Tcl, mas é possível usá-la também com outras linguagens de script como Perl ou Python.

14.2. O Interpretador Tcl

Tcl é uma linguagem de script dinâmica isto significa que o código fonte que você escreve usando Tcl não é compilado [2] em um arquivo binário que possa ser executado por conta própria. Mas é armazenado como um conjunto de instruções (comandos) escrito em um ou mais arquivos de texto simples, os quais são interpretados no momento da execução pelo interpretador Tcl.

O interpretador Tcl nada mais é do que um programa binário (compilado) que pode compreender e processar os scripts escritos em Tcl.

Para rodar em uma uma plataforma específica (Linux, Windows, Mac etc) é necessário um interpretador para a respectiva plataforma.

Cada interpretador Tcl em execução deve ser considerado como uma máquina virtual separada e com seu próprio estado interno que é, consequentemente, modificado na medida que chegam os comandos.

Os comandos podem ser lidos a partir de um arquivo contendo um script ou pela entrada padrão (terminal) permitindo interagir com o interpretador de maneira dinâmica.

A figura seguinte mostra a chamada do interpretador Tcl pelo terminal pelo comando tclsh85 e após o prompt % a execução do comando info patchlevel.

Figura 76. Chamada do interpretador Tcl em um terminal e a execução de alguns comandos. (Fonte: Tcl 8.5 Networking Programming, 2010)

Chamada do interpretador Tcl em um terminal e a execução de alguns comandos. (Fonte: Tcl 8.5 Networking Programming, 2010)


O comando tclsh85 é usado para refletir a versão instalada do interpretador, mas poderia ser também tclsh, e o comando info patchlevel retorna informações sobre a versão do interpretador instalado e o comando exit encerra a execução do interpretador. (Fonte: Tcl 8.5 Networking Programming, 2010)

Junto com o interpretador tclsh existe outro aplicativo chamado wish, que além de executar os comandos da Tcl também carrega o pacote Tk que permite criar os widgets

14.2.1. Instalação da Tcl/Tk

14.2.1.1. Em ambiente Windows

A instalação em ambiente Windows é feita com um executável do tipo ActiveTcl8.5.11.0.295402-win32-ix86-threaded.exe, versão disponível no momento em que escrevo este parágrafo (24/01/2012), na área de downloads da empresa ActiveState.

Depois de baixar e executar o programa , você a tela do instalador semelhante ao mostrado na figura a seguir.

Figura 77. Tela inicial do instalador do interpretador Tcl ActiveTcl em ambiente Windows.(Fonte: Tcl 8.5 Networking Programming, 2010)

Tela inicial do instalador do interpretador Tcl ActiveTcl em ambiente Windows.(Fonte: Tcl 8.5 Networking Programming, 2010)


Uma das vantagens deste programa é a possibilidade de escolher o diretório de instalação permitindo que você instale na sua área de usuário sem a necessidade de ser administrador da sua máquina. ;^)

14.2.1.2. Em ambiente Linux

Para o Linux você pode baixar o interpretador do site da ActiveState ou os pacotes da sua distribuição além de uma infinidade de pacotes desenvolvidos pela Comunidade de Software Livre.

Por exemplo, para você ter uma idéia das opções de pacotes disponíveis sobre Tcl no Debian 5.0 - Lenny que estou usando, uso o comando:

apt-cache search tcl | grep Tcl

Procuro todos os pacotes relacionados com tcl e filtro a saída com o comando grep para exibir apenas as linhas onde aparece a string Tcl explícita e encontro a seguinte listagem:

libtcl-chiark-1 - Tcl interfaces for adns, cdb, crypto, etc.
tclcsound - Tcl bindings and interpreters for Csound
gpsmanshp - A Tcl interface to shapelib
libgv-tcl - Tcl bindings for graphviz
hfsutils-tcltk - Tcl/Tk interfaces for reading and writing Macintosh volumes
xhtml2ps - HTML to PostScript converter (Tcl/Tk GUI frontend)
tcl8.4-insighttoolkit3 - Image processing toolkit for registration and segmentation - Tcl bindings
itcl3.1-dev - [incr Tcl] OOP extension for Tcl 8.3 - development files
itcl3.1-doc - [incr Tcl] OOP extension for Tcl 8.3 - manual pages
itcl3.1 - [incr Tcl] OOP extension for Tcl 8.3 - run-time files
iwidgets3.1-doc - [incr Widgets] OOP extension for Tcl/Tk 8.3 - manual pages
iwidgets3.1 - [incr Widgets] OOP extension for Tcl/Tk 8.3 - run-time files
itcl3-dev - [incr Tcl] OOP extension for Tcl - development files
itcl3-doc - [incr Tcl] OOP extension for Tcl - manual pages
itcl3 - [incr Tcl] OOP extension for Tcl - run-time files
libtk-img-dev - Extended image format support for Tcl/Tk (development files)
libtk-img-doc - Extended image format support for Tcl/Tk (manual pages)
libtk-img - Extended image format support for Tcl/Tk (runtime)
libmemchan-tcl-dev - Tcl extension for in-memory channels - development files
libmemchan-tcl - Tcl extension for in-memory channels - runtime library
mysqltcl - Interface to the MySQL database for the Tcl language
newt-tcl - A newt module for Tcl
pfm - PostgreSQL graphical client using Tcl/Tk
libpgtcl-dev - Tcl client library binding for PostgreSQL - development files
libpgtcl1.5 - Tcl client library binding for PostgreSQL
plplot-tcl-dev - Tcl/Tk development support for PLplot, a plotting library
plplot-tcl - Tcl/Tk support for PLplot, a plotting library
rrdtool-tcl - Time-series data storage and display system (Tcl interface)
libtcltk-ruby - Tcl/Tk interface for Ruby
libtcltk-ruby1.8 - Tcl/Tk interface for Ruby 1.8
libtcltk-ruby1.9 - Tcl/Tk interface for Ruby 1.9
sbnc-tcl - an IRC proxy for multiple users (Tcl extension)
libsetools-tcl - SETools Tcl bindings
libsnack2-alsa - Sound extension to Tcl/Tk and Python/Tkinter - Tcl/Tk library
libsnack2-dev - Sound extension to Tcl/Tk and Python/Tkinter - development files
libsnack2-doc - Sound extension to Tcl/Tk and Python/Tkinter - documentation
libsnack2 - Sound extension to Tcl/Tk and Python/Tkinter - Tcl/Tk library
python-tksnack - Sound extension to Tcl/Tk and Python/Tkinter - Python library
libsqlite3-tcl - SQLite 3 Tcl bindings
libsqlrelay-tcl - SQL Relay Tcl API
sufary-tcltk - Tcl/Tk interface for SUFARY
tcl8.3-dev - Tcl (the Tool Command Language) v8.3 - development files
tcl8.3-doc - Tcl (the Tool Command Language) v8.3 - manual pages
tcl8.3 - Tcl (the Tool Command Language) v8.3 - run-time files
tcl8.4-dev - Tcl (the Tool Command Language) v8.4 - development files
tcl8.4-doc - Tcl (the Tool Command Language) v8.4 - manual pages
tcl8.5-dev - Tcl (the Tool Command Language) v8.5 - development files
tcl8.5-doc - Tcl (the Tool Command Language) v8.5 - manual pages
tcl8.5 - Tcl (the Tool Command Language) v8.5 - run-time files
tclcurl - Tcl bindings to libcurl
tclex - A lexical analyzer generator for Tcl
tclgeoip - Tcl extension implementing GeoIP lookup functions
tcllib - the Standard Tcl Library
tclodbc - The ODBC extension to Tcl
tclreadline - GNU Readline Extension for Tcl/Tk
tclthread - Tcl extension implementing script level access to Tcl threading capabilities
tk-dev - The Tk toolkit for Tcl and X11 (default version) - development files
tk-doc - The Tk toolkit for Tcl and X11 (default version) - manual pages
tk - The Tk toolkit for Tcl and X11 (default version) - run-time files
tcl-tls - the TLS OpenSSL extension to Tcl
libtrf-tcl-dev - Tcl data transformations - development files
libtrf-tcl-doc - Tcl data transformations - development files
libtrf-tcl - Tcl data transformations - runtime library
libudp-tcl - UDP sockets for Tcl
tclvfs - Exposes Tcl 8.4's virtual filesystem C API to the Tcl script level
tclx8.3-doc - Extended Tcl (TclX) version 8.3.5 -- TclX manpages
tclx8.3 - Extended Tcl (TclX) version 8.3.5 -- TclX runtime package
tkx8.3-dev - Extended Tcl (TclX) version 8.3.5 -- TkX development package
tkx8.3-doc - Extended Tcl (TclX) version 8.3.5 -- TkX manpages
tclx8.4-dev - Extended Tcl (TclX) - development package
tclx8.4-doc - Extended Tcl (TclX) - manpages
tclx8.4 - Extended Tcl (TclX) - shared library
tclxml - Tcl library for XML parsing
tdom-dev - A fast XML/DOM/XPath/XSLT extension for Tcl written in C - development files
tdom - A fast XML/DOM/XPath/XSLT extension for Tcl written in C
tk8.3-dev - Tk toolkit for Tcl and X11, v8.3 - development files
tk8.3-doc - Tk toolkit for Tcl and X11, v8.3 - manual pages
tk8.4-dev - Tk toolkit for Tcl and X11, v8.4 - development files
tk8.4-doc - Tk toolkit for Tcl and X11, v8.4 - manual pages
tk8.5-dev - Tk toolkit for Tcl and X11, v8.5 - development files
tk8.5-doc - Tk toolkit for Tcl and X11, v8.5 - manual pages
tk8.5 - Tk toolkit for Tcl and X11, v8.5 - run-time files
tkcon - Enhanced interactive console for developing in Tcl
tkgate-data - Event driven digital circuit simulator with Tcl/Tk
tkgate-doc - Event driven digital circuit simulator with Tcl/Tk
tkgate - Event driven digital circuit simulator with Tcl/Tk
tkinfo - Tcl/Tk Info browser
libtktable2.9 - Table extension for Tcl/Tk
vtk-examples - C++, Tcl and Python example programs/scripts for VTK
vtk-tcl - Tcl bindings for VTK
tclxapian - Xapian search engine interface for Tcl
xotcl-dev - Extended Object Tcl (XOTcl): Object orientation for Tcl - development files
xotcl-doc - Extended Object Tcl (XOTcl): Object orientation for Tcl - manual
xotcl-shells - Extended Object Tcl (XOTcl): Object orientation for Tcl - shells
xotcl - Extended Object Tcl (XOTcl): Object orientation for Tcl - shared library
aolserver4-xotcl - Extended Object Tcl (XOTcl): orientação a objetos para o AOLServer - módulo
ewipe - Mais outra ferramenta de apresentação baseada em Tcl/Tk
tk8.4 - kit de ferramentas Tk para Tcl e X11, v8.4 - arquivos em tempo de execução
blt - a biblioteca de extensão BLT para Tcl/Tk - pacote de execução
cableswig - gera invólucros para Python e Tcl a partir de código C++
amsn - um mensageiro MSN escrito em Tcl
aolserver4-nscache - módulo AOLserver 4: API Tcl para os Caches do AOLserver
tclx8.3-dev - Tcl Estendido versão 8.3.5 -- pacote de desenvolvimento TclX
tkx8.3 - Tcl estendido (TclX) versão 8.3.5 -- pacote de tempo de execução TkX
tcl8.4 - Tcl (Tool Command Language) v8.4 - arquivos de tempo de execução
tkdvi - Um previsualizador TeX DVI baseado em Tcl/Tk.
blt-dev - a biblioteca de extensão BLT para Tcl/Tk - arquivos de desenvolvimento
bwidget - um conjunto de "widgets" de extensão para Tcl/Tk
blt-demo - a biblioteca de extensão BLT para Tcl/Tk - demonstrações e exemplos
bookview - cliente NDTP (Network Dictionary Transfer Protocol) baseado em Tcl/Tk
postgresql-pltcl-8.3 - PL/Tcl procedural language for PostgreSQL 8.3
libdb4.8-tcl - Berkeley v4.8 Database Libraries for Tcl [module]
postgresql-pltcl-8.4 - PL/Tcl procedural language for PostgreSQL 8.4
libtcltk-ruby1.9.1 - Tcl/Tk interface for Ruby 1.9.1
znc-tcl - an advanced IRC bouncer (Tcl extension)

Quer mais? :^)

Por exemplo, para instalar no Debian todos os pacotes (binários, documentação e desenvolvimento) da versão 8.5 do Tcl e Tk basta rodar o comando (como root):

bash# apt-get install tcl8.5 tcl8.5-dev tcl8.5-doc tk8.5 tk8.5-dev tk8.5-doc

E em seguida executar o interpretador de Tcl puro com o comando tclsh ou associado com a biblioteca Tk com o comando wish.

14.2.1.3. Instalação de Bibliotecas ou Pacotes (Packages)

Os pacotes, ou extensões, oferecem novas funcionalidades para o programador e podem ser instaladas de duas formas, compilando o código fonte ou instalando um pacote pré-compilado.

Esses pacotes precisam ser instalados em locais pré-definidos onde o interpretador Tcl procura por pacotes. A variável especial auto_path armazena a lista de diretórios onde o interpretador procura por pacotes.

Podemos visualizar o conteúdo da variável auto_path abrindo o interpretador no modo interativo e executando o comando puts $auto_path

bash$ tclsh
% puts $auto_path
/usr/share/tcltk/tcl8.4 /usr/lib /usr/local/lib/tcltk /usr/local/share/tcltk /usr/lib/tcltk /usr/share/tcltk
%

O ActiveTcl vem com um utilitário prático chamado Teacup que facilita a instalação de pacotes pré-compilados localiza o(s) pacote(s) e verificando dependências. O Teacup utiliza um repositório externo chamado Teapot mantido pela empresa ActiveState.

14.3. Comandos e Argumentos

A linguagem Tcl é de fácil aprendizado e com muitos recursos. O próprio interpretador oferece dicas sobre a sintaxe correta dos comandos.

Por exemplo, se você digitar apenas o comando puts terá o seguinte retorno:

% puts
wrong # args: should be "puts ?-nonewline? ?channelId? string"

Nesta mensagem o interpretador está informando que o comando puts exige uma string e aceita alguns argumentos opcionais (entre sinais de interrogação) nonewline e channelID.

O interpretador Tcl lida apenas com comandos (instruções) e argumentos. Cada linha distinta começa com um comando seguido do(s) argumento(s) necessários. Se a linha ficar muito grande, encerre a linha com o indicador de continuação de linha ("\" barra invertida).

Por exemplo:

 button .b1 -text "Meu primeiro botão" -command { exit }
 pack .b1

ou

 button .b1 \ 
-text "Meu primeiro botão" \ 
-command { exit }
 pack .b1

Vai gerar um botão, figura abaixo, que irá fechar o interpretador ao ser clicado.

Figura 78. Botão

Botão


Nota

Para testar o código acima, no Linux, abra um terminal e digite wish para abrir o interpretador em modo interativo. No prompt (%) que aparecer digite os comandos.

Além da barra invertida, itens entre chaves ({ e }) podem ultrapassar várias linhas, conforme o if abaixo:

 
if {$i<5} then { 
puts "$i é menor que 5" 
}

O comando if acima é uma linha para o Tcl.

Comandos e argumentos são separados por espaços, mas se você quiser colocar espaços em um argumento, pode colocar todo o argumento entre aspas:

puts "$i é menor que 5"

14.4. Variáveis em Tcl

Como toda linguagem de programação o Tcl permite que você armazene um valor (ou uma lista de valores) em uma variável, a qual recebe um nome para ser identificada e para a qual se atribui um conteúdo para ser armazenado. Para a atribuição de valor para uma variável use o comando set.

set var 6

No comando acima o valor "6" foi atribuído à variável chamada "var".

Quando você digitar o comando, notará que o wish imprimirá o valor atribuído à variável.

% set var 6
6

Variáveis em Tcl são armazenadas como strings, embora o exemplo anterior pudesse enganá-lo fazendo achar que fosse um número.

A string "Maria" também pode ser armazenada na variável "var".

% set var Maria
Maria

14.5. Vendo o conteúdo de uma variável.

Para ler o conteúdo de uma variável utilize o caracter "$" (cifrão)

O cifrão significa a substituição de variável, por isso coloque $ antes do nome da variável, por exemplo $var, para que o interpretador substitua o valor atual mantido em var.

Experimente:

puts var

e compare com

puts $var 

O comando puts é a abreviação de put string e imprime o argumento na saída padrão, terminal.

14.6. Operações matemáticas

O comando expr é usado para operações matemáticas.

expr 2 * 6

ou

expr 2 * $var

Quando precisar salvar o resultado de um comando e usar o resultado como argumento para outro comando use os colchetes "[" e "]".

set var2 [expr 2 * 6]

ou

set var2 [expr 2 * $var]

No código anterior a parte [expr 2 * 6] é executada primeiro, e o resultado 12 é substituído para formar o comando set var2 12

Os colchetes também podem ser usados dentro de aspas.

% puts "O resultado de 2 x 6 é [expr 2 * 6]"
O resultado de 2 x 6 é 12
%

Basicamente todas as variáveis em Tcl são consideradas como string e a Tcl converte o valor de uma variável para o tipo adequado no momento da execução.

Por exemplo:

set x "2"; expr $x + 3                     
5
% set x "texto"; expr $x + 3
syntax error in expression "texto + 3": variable references require preceding $

Na primeira linha a string 2 foi convertida para um tipo inteiro pelo comando expr e retorna o valor correto. Mas no segunda caso a string texto gera uma mensagem de erro porque não pode ser convertida.

Portanto o conteúdo de uma variável pode ser tratada como um número, uma string ou um valor lógico, dependendo do contexto.

14.7. Listas

Uma lista é uma sequência ordenada de elementos tais como strings, outras listas, e outras variáveis. Para criar uma lista, você pode usar o comando list:

% set minhaLista [list elemento1 elemento2 elemento3]
elemento1 elemento2 elemento3
% 

Neste exemplo criamos uma lista com três elementos, separados por espaços em branco e atribuímos a lista à variável minhaLista.

Mas uma lista também pode ser criada com o comando:

% set minhaLista "elemento1 elemento2 elemento3"
elemento1 elemento2 elemento3
%

Você poderá perguntar: Então qual a utilidade do comando list?

A vantagem do comando list é que ele cuida da formatação correta, acrescentando chaves e barras invertidas quando necessário.

O uso de listas permite organizar e estruturar além de permitir o uso de vários comandos que manipulam listas.

O comando llength retorna o número de elementos de uma lista.

% set minhaLista [list elemento1 elemento2 elemento3]
elemento1 elemento2 elemento3
% llength $minhaLista
3

O comando lindex retorna o elemento de uma lista. O comando recebe como argumento a lista e um índice.

% set minhaLista [list elemento1 elemento2 elemento3]
elemento1 elemento2 elemento3
% lindex $minhaLista 0
elemento1
% lindex $minhaLista 1
elemento2
% lindex $minhaLista 2
elemento3

Também é possível criar uma lista com sublista(s).

% set minhaLista [list 1 2 [list outra lista aqui]]
1 2 {outra lista aqui}

E resgatar elementos da lista e da(s) sublista(s) (com um índice adicional).

% set minhaLista [list 1 2 [list outra lista aqui]]
1 2 {outra lista aqui}
% lindex $minhaLista 1
2
% lindex $minhaLista 2
outra lista aqui
% lindex $minhaLista 2 1
lista

14.8. Controlando o fluxo do programa (if-then)

A linguagem Tcl oferece comandos que permitem desvios e instruções tais como if-then (se-então), for (até que) e while (enquanto).

O formato básico de um comando if é:

if {condição} then {instruções}

Exemplo:

set x 0 
if {$x < 10} then { 
puts "$x é menor que 10" 
}

Se o resultado da condição {$x < 5} for verdadeiro (1), então as instruções serão executadas. Se o resultado da condição for falso (0), então as instruções não serão executadas.

14.9. Controlando o fluxo do programa (for)

O formato básico de um comando for é:

for {início} {condição} {incremento} {instrução}

for {set x 0} {$x < 5} {incr x} {puts "x vale $x"}

ou

for {set x 0} {$x < 5} {incr x} { 
puts "x vale $x" 
}
% for {set x 0} {$x < 5} {incr x} {puts "x vale $x"}
x vale 0
x vale 1
x vale 2
x vale 3
x vale 4
% 

Neste caso a variável x é inicializada com o valor 0 e se a condição {$x < 5} for verdadeira a instrução puts "x vale $x" é executada.

Em seguida é executado o comando incr x, incrementando em uma unidade o conteúdo da variável x. Novamente a condição {$x < 10} é avaliada, se for verdadeira repete-se o ítem anterior e se for falsa o loop é encerrado.

14.10. Controlando o fluxo do programa (while)

O formato básico de um comando while é:

while {condição} {instrução}

Exemplo:

set x 0
while {$x < 10} {
puts "x vale $x"
incr x
}

A variável x é inicializada com o valor 0, em seguida é feito um teste, se {$x < 10} for verdadeiro são executadas as instruções puts "x vale $x" e incr x.

Em cada passagem pelo loop, o valor de x é incrementado em uma unidade, enquanto x for menor que 10, até o conteúdo da variável x for igual a 10, quando então o loop while é encerrado.

14.11. O loop foreach

O foreach é usado para interagir com listas, executando um comando ou um script para cada item de uma lista de itens.

Possui a seguinte sintaxe:

foreach variável lista { comandos }

% foreach numero {1 2 3 4 5} { puts "porta serial $numero" }
porta serial 1
porta serial 2
porta serial 3
porta serial 4
porta serial 5

Em cada iteração o loop foreach atribui a uma variável um elemento da lista, percorrendo-a até que todos os itens da lista tenham sido lidos.

O script seguinte faz a mesma coisa, porém, não recebe uma lista diretamente e sim uma variável que contém uma lista (numeros).

% set numeros {1 2 3 4 5}
1 2 3 4 5
% foreach numero $numeros { puts "porta serial $numero" }
porta serial 1
porta serial 2
porta serial 3
porta serial 4
porta serial 5
% 

O foreach também pode iteragir com duas listas simultâneamente.

% set numeros {1 2 3 4 5}
1 2 3 4 5
% set inst {pHmetro bomba válvula espectrofotômetro balança}
pHmetro bomba válvula espectrofotômetro balança
% foreach numero $numeros instrumento $inst {
puts "$instrumento usa porta serial $numero"
}
pHmetro usa porta serial 1
bomba usa porta serial 2
válvula usa porta serial 3
espectrofotômetro usa porta serial 4
balança usa porta serial 5
% 

14.12. Redigindo seus próprios procedimentos

O comando proc registra um procedimento por nome e permite que você o execute como qualquer outro comando em Tcl. A sintaxe é:

proc nome_do_procedimento {argumentos} {instruções}

Exemplo:

proc somar_dois { valor } {
return [expr $valor + 2]
}

A partir daí o procedimento somar_dois estará pronto para ser usado a qualquer momento no futuro.

Por exemplo:

somar_dois 5
7

Exercício 2

Desenvolver, em Tcl, um programa que calcule a soma dos N números inteiros (1, 2, 3, ... N) e mostre o resultado final.

Vamos lembrar do diagrama de fluxo do exercício 1 e implementar aquela lógica usando a linguagem Tcl.

Resolução! Mas antes tente fazer ! :)

Sugestão crie um procedimento do tipo:proc soma { N } { ... }

14.13. Criando Arquivos Script para Tcl

Antes de continuar, vamos digitar os comandos em um arquivo texto usando um editor de texto puro (Notepad - Windows), (Emacs - Linux) e salvar com o nome exemplo.tcl.

#!/bin/sh
#A próxima linha reinicia usando o wish \
    exec wish "$0" "$@"

proc soma { N } {
    set A 0
    set B 0
    while {$A < $N} {
	incr A
	set B [expr $B + $A]
    }
    puts "A soma dos $N primeiros números inteiros é $B"
}


soma 1
soma 2
soma 4
soma 5

A primeira linha do script exemplo.tcl usa um truque interessante do Linux. Colocando um comentário especial na primeira linha de um script, começando com #!, o shell Linux passará o arquivo script para o programa adequado, neste caso o wish.

A etapa seguinte para fazer o script rodar é tornar o arquivo exemplo.tcl executável. Em um terminal digite:

chmod +x exemplo.tcl

E o script poderá ser executado a partir da linha de comando como qualquer outro programa.

14.13.1. O Cabeçalho de um Script

A presença dos dois caracteres #! (shebang em inglês) no início de um arquivo executável informa o carregador do programa que o arquivo é um script e também especifica o interpretador que deve ser usado para executá-lo.

O capeçalho do tipo #!/usr/bin/tclsh especifica que o script deve ser interpretado pelo programa tclsh (ou #!/usr/bin/wish) cujo path é /usr/bin. No entanto se você tentar rodar esse script em um sistema onde o tclsh não estiver no diretório /usr/bin ele não vai rodar e portanto essa não é uma boa estratégia pois torna o código pouco portável. [3]

Uma alternativa mais conveniente é usar:

  
#!/bin/sh
#Script exemplo \
exec tclsh "$0" "$@"

Neste caso o script é interpretado pelo shell sh que é incapaz de executar os comandos Tcl mas vai executar o comando exec.

O comando exec chama o interpretador tclsh e passa os argumentos $0 (nome do script) e $@ (demais argumentos passados para o shell).

O truque neste caso é evitar que a Tcl execute o comando exec (um comando também da Tcl) mas apenas o sh execute o comando exec. Para evitar que isso aconteça usa-se a barra invertida \ no final da segunda linha para que a Tcl considere a segunda e terceira linha como um único comentário. Enquanto que o sh considera apenas a segunda linha como comentário e a terceira linha como um comando a ser executado. ;^)

Uma outra alternativa que vem ganhando popularidade é:

  
#!/usr/bin/env tclsh
#Script exemplo
puts "Oi Mundo!"

O comando env executa o comando tclsh usando a avariável PATH do sistema.

Mas para usar os widgets Tk, é necessário usar o interpretador wish:

  
#!/bin/sh
#Script exemplo \
exec wish "$0" "$@"

ou

  
#!/usr/bin/env wish
#Script exemplo
puts "Oi Mundo!"

14.14. Acessando Arquivos - Entrada e Saída de Dados

Para acessar um arquivo, ou seja, ler ou escrever dados, é preciso criar um canal para o arquivo, o que é feito em Tcl com o comando open.

O comando open gera (ou retorna) um descritor de arquivo ou identificador), ou seja, um nome para o canal que será usado para ler ou escrever dados no arquivo.

Por exemplo, se eu tiver um arquivo chamado arquivo.txt posso criar um canal para esse arquivo digitando em um terminal o comando:

% open arquivo.txt
file5

E a Tcl cria automaticamente o identificador file5 para o canal criado para acessar o arquivo.txt.

Na prática esse nome é armazenado em uma variável para ser usado posteriormente em operações de leitura e escrita:

% set nome_canal [open arquivo.txt]
file5
% puts $nome_canal
file5
% 

No exemplo acima criei um canal para arquivo.txt e armazenei o identificador na variável nome_canal, cujo conteúdo pode ser visualizado com o comando puts $nome_canal.

Outro aspecto importante na manipulação de arquivos é o modo de acesso que pode ser: somente leitura, somente escrita ou leitura e escrita.

O modo de acesso pode ser definido com o uso dos parâmetros: r, r+, w, w+, a e a+.

A tabela seguinte resume os diferentes modos de acesso do comando open.

Tabela 5. Parâmetros do comando open e os diferentes modos de acesso de um canal.

ParâmetroLeituraEscritaPosição inicial do ponteiro (ou cursor)Arquivo deve existir?Conteúdo do arquivo é apagado?
rSimNãoInício do arquivoSimNão
r+SimSimInício do arquivoSimNão
wNãoSimInício do arquivoNãoSim
w+SimSimInício do arquivoNãoSim
aNãoSimFim do arquivoNãoNão
a+SimSimFim do arquivoNãoNão

Em resumo: (Fonte: Tcl/Tk - Programação Linux, 2005)

  • r - Abre o arquivo apenas para leitura, e o arquivo deve existir.

  • r+ - Abre o arquivo para leitura e escrita (gravação) e o arquivo deve existir.

  • w - Abre o arquivo para gravação não-incremental, ou seja, se o arquivo já existir seu conteúdo original será apagado e serão escritos novos dados.

  • w+ - Abre o arquivo para leitura e gravação não-incremental.

  • a - Abre o arquivo para gravação incremental, ou seja, se o arquivo já existir, seu conteúno não será apagado e qualquer novo dado escrito será adicionado a partir do final do arquivo.

  • a+ - Abre o arquivo para leitura e gravação incremental.

Por exemplo, vou criar um arquivo redirecionando a saída do comando ls para o arquivo arquivos.txt.

$ ls > arquivos.txt

Em seguida vamos criar sript que vamos chamar ler_arquivo.tcl que vai abrir um canal para o arquivo arquivos.txt e exibir o seu conteúdo na tela.

#!/usr/bin/env tclsh
#Script ler_arquivo.tcl

  set nome_canal [ open arquivos.txt r ]

  while { ! [ eof $nome_canal ] } {
         set linha [ gets $nome_canal ]
         puts "Esta linha contém: $linha"
  }

Vou alterar as permissões [4] deste script para torná-lo executável com o comando:

$ chmod 744 ler_arquivo.tcl

E ao executar este script em um terminal vemos o conteúdo do arquivo arquivos.txt:

$ ./ler_arquivo.tcl 
Esta linha contém: arquivos.txt
Esta linha contém: medidor_multiparametro_00.tcl
Esta linha contém: medidor_multiparametro_00.tcl~
Esta linha contém: medidor_multiparametro.db
Esta linha contém: multipar00.tcl
Esta linha contém: multipar00.tcl~
Esta linha contém: objLab
Esta linha contém: simu_orion.tcl
Esta linha contém: teste.csv
Esta linha contém: 

O script ler_arquivo.tcl abre o arquivo arquivos.txt somente para leitura (r) e em seguida entra em um loop while enquanto o final do arquivo não for atingido. Para isso foi usado o comando eof em conjunto com o operador de negação (!). O comando gets serve para ler a próxima linha do canal e armazena o que foi lido na variável linha. E finalmente o comando puts exibe na tela a mensagem Esta linha contém: seguido do conteúdo da variável linha. Esses comandos são executados até que o final do arquivo seja encontrado. (Fonte: Tcl/Tk - Programação Linux, 2005)

14.15. Usando a biblioteca Tk

14.15.1. Incluindo um button

Vamos criar um botão que vai chamar a execução do programa anterior, para tanto, vamos anexar as linhas abaixo:

button .b1 -text "Executar o programa soma" -command {soma 5}
pack .b1

Na primeira linha o comando button cria um botão chamada .b1 (o ponto é importante).

Assim como o Linux usa o caractere (/) para marcar o diretório raiz do sistema de arquivos a Tcl usa o ponto (.) para marcar o widget raiz (a janela principal do seu aplicativo).

Estamos então criando um widget button (.) que se comporta como um widget filho do widget pai (.).

A opção -command determina qual o comando Tcl que irá funcionar quando o botão for "clicado", neste caso ele chama o procedimento soma com o argumento 5.

Os widgets são criados mas permanecem invisíveis até que um comando de gerenciamento de geometria seja usado, neste caso pack.

#!/bin/sh
#A próxima linha reinicia usando o wish \
    exec wish "$0" "$@"
proc soma { N } {
    set A 0
    set B 0
    while {$A < $N} {
	incr A
	set B [expr $B + $A]
    }
    puts "A soma dos $N primeiros números inteiros é $B"
}

button .b1 -text "Executar o programa soma" -command {soma 5}
pack .b1

Ao executar o programa acima em um terminal, você verá o botão que irá chamar o programa ao ser clicado, exibindo no terminal a mensagem A soma dos 5 primeiros números inteiros é 15

Figura 79. Botão para execução do programa soma.

Botão para execução do programa soma.


14.15.2. Incluindo um entry.

Do jeito que o programa está o valor de N é fixo e vale 5.

Para poder rodar o programa com diferentes valores de N vamos usar um widget chamado entry(entrada).

Para isso basta incluir a linha:

entry .entrada -relief sunken -background white -textvariable N

Onde entry é o comando de criação do widget com o nome .entrada.

A opção -relief define o relevo 3D do widget e pode assumir as opções: flat, groove, raised, ridge, sunken.

A opção -background define a cor de fundo e finalmente a opção -textvariable permite definir uma variável (N) que vai armazenar o que o usuário digitar dentro do entry.

Só falta substituir o número 5 pelo conteúdo da variável N ($N) na linha de criação do botão.

#!/bin/sh
#A próxima linha reinicia usando o wish \
    exec wish "$0" "$@"


proc soma { N } {
    set A 0
    set B 0
    while {$A < $N} {
	incr A
	set B [expr $B + $A]
    }
    puts "A soma dos $N primeiros números inteiros é $B"
}


button .b1 -text "Executar o programa soma" -command {soma $N}
pack .b1

entry .entrada -relief sunken -background white -textvariable N
pack .entrada

Figura 80. Botão para execução do programa soma com o campo de entrada de número.

Botão para execução do programa soma com o campo de entrada de número.


14.15.3. Incluindo um text.

Agora vamo incluir o widget text na própria janela do programa para que a saída seja exibida na interface gráfica.

#!/bin/sh
#A próxima linha reinicia usando o wish \
exec wish "$0" "$@"
#exemplo.tcl
entry .entrada -relief sunken -background white -textvariable N
pack .entrada
button .b1 -text "Executar o programa soma" -command {soma $N}
pack .b1

text .texto -background white -foreground black -width 50 -height 10

pack .texto

proc soma { N } {
set A 0
set B 0
while {$A < $N} { 
incr A 
set B [expr $B + $A]
}

.texto insert end "A soma dos $N primeiros números inteiros é $B\n"

}

Deixei em destaque as linhas adicionadas para criar o widget text.

A primeira linha:

text .texto -background white -foreground black -width 50 -height 10

cria o widget text com o nome .texto, com fundo branco (-background white), letras pretas (-foreground black), largura 50 (-width 50) e altura 10 (-height 10).

A segunda linha, pack .texto, usa o gerenciador de posição pack para exibir o widget .texto.

E finalmente troquei o comando

puts "A soma dos $N primeiros números inteiros é $B"

pelo comando

.texto insert end "A soma dos $N primeiros números inteiros é $B"

para inserir o resultado diretamente no final (end) do widget .texto.

Figura 81. Tela do programa soma após a inclusão do texto.

Tela do programa soma após a inclusão do texto.


Espero ter ajudado a dar os seus primeiros passos com a linguagem Tcl/Tk. A partir de agora vamos mostrar algumas aplicações dessa linguagem para a Automação em Laboratório, que é o nosso tema principal!

14.16. Links sobre Tcl/Tk

Curso sobre Tcl/Tk - Curso em português sobre Tcl/Tk.

Curso sobre Tcl/Tk do Rildo Pragana - Informações em português sobre Tcl/Tk

Site do Rildo Pragana - Muitos programas escritos em Tcl/Tk

SITE OFICIAL - Site Oficial da linguagem Tcl, criada por John K. Ousterhout.

Documentação no site oficial.

Site sobre Tcl/Tk do Ricardo Jorge - Neste site você encontra diversos links e informações sobre a Tcl/Tk

Site sobre Tcl/Tk do Wesley R. Braga - Páginas de manual da Tcl/Tk.

SITE WIKI SOBRE TCL/TK - Site Wiki (com conteúdo editável pelos visitantes) sobre Tcl/Tk

WIKI - TCL- Site Wiki sobre Tcl em português.



[2] Compilação é conversão (ou tradução) do código fonte de uma linguagem de programação de alto nível para uma linguagem de programação de baixo nível.

Normalmente, o código fonte é escrito em uma linguagem de programação de alto nível (compreensível para humanos) e o código compilado é escrito em uma linguagem de baixo nível como uma sequência de instruções a ser executada pelo microprocessador. (Fonte: Wikipedia)

[3] Portabilidade de um programa de computador é a sua capacidade de ser compilado ou executado em diferentes sistemas (Linux, Windows etc).

[4] O Linux é um sistema multiusuário o que significa que um mesmo PC ou servidor pode ser acessado por vários usuários simultâneamente. Com isto, surge a necessidade de algum sistema de segurança que limite o que cada usuário pode fazer no sistema, para que não haja o risco de que um usuário possa destruir arquivos ou configurações do sistema ou de outros usuários. Isto é feito através das permissões de arquivos. (Fonte: Entendendo e Dominando o Linux)

Veja com mais detalhes uma explicação bem completa sobre permissões de acesso no Guia Foca Linux