Widgets devem interagir entre si para realizarem
sua funcionalidade completa. Por exemplo, um objeto tipo text,
listbox
ou canvas
, usualmente é empregado em conjunto com
um ou mais scrollbars.
Estes permitem visualizar partes daqueles
objetos que de outra forma seriam invisíveis, quando o tamanho do que queremos
mostrar é maior que o espaço disponível na tela. Para mostrar o conceito,
suponha que temos duas listas (listboxes)
situadas lado-a-lado,
uma delas com ítens textuais que queremos escolher e passar para a outra ou
devolver (desselecionar). Esse tipo de comportamento é útil, por exemplo, num
programa que escolherá quais arquivos a empacotar na criação de um arquivo
.tar.gz
.
Inicialmente, queremos criar bitmaps para colocar nos botões (melhor que
deixar um texto, neste caso). Uma forma possível de fazer isso é editar o
bitmap com algum editor gráfico e salvar no formato xbm, que
é simplesmente um texto que pode ser incluido em um programa C, ou também no
tcl, o que nos interessa. Escolhemos dimensões 16x16 pixels para estas
imagens. Para deixá-los disponíveis em um widget tcl/tk, precisamos primeiro
criar o objeto image
, com o seguinte comando:
image create bitmap left -data "<dados do arquivo .xbm>"
onde left
é o nome da imagem criada. A figura pode ser incluida
com o editor de textos, entre aspas, onde está o comentário agora. Use o programa bitmap (que vem com a distribuição do
X11) para criar os arquivos left.xbm e right.xbm, e depois inclua-os no seu
programa como mostrado. De forma similar, procedemos com a imagem
right
, a seta desenhada no outro sentido. Assim, podemos criar
os botões com imagens no lugar dos textos:
button .b1 -image right button .b2 -image left
Eventualmente, falta atribuir comandos a serem executados por estes botões,
mas vamos discutir primeiro o restante da interface visual. Os
listboxes
devem, para melhor simplicidade de operação, permitir
seleção de múltiplos ítens, o que é conseguido com a opção -selectmode
extended
. No final da definição da interface, carregaremos um deles
com a lista de estados brasileiros, que serão nossos dados a selecionar.
Vejamos:
listbox .lb1 -selectmode extended listbox .lb2 -selectmode extended pack .lb1 -side left pack .lb2 -side right pack .b2 .b1 -side bottom -expand 1 -padx 10 .lb1 insert end pernambuco paraiba "rio grande do norte" ceará alagoas piauí \ sergipe bahia pará amazonas maranhão tocantins goias "distrito federal" \ "minas gerais" "mato grosso" "mato grosso do sul" "rio de janeiro" \ "espírito santo" "roraima" "acre" "são paulo" paraná \ "santa catarina" "rio grande do sul" amapá rondônia
Observe que os comandos pack
devem ter uma certa ordem, como já
vimos, para garantir o posicionamento dos botões no centro da interface. A
opção -expand 1
faz com que o espaço disponível seja distribuido
igualmente entre os botões.
Agora vejamos a execução dos comandos dos botões. O botão superior
(.b1),
quando pressionado, deverá retirar os ítens selecionados
no listbox da esquerda (.lb1)
e inseri-los no listbox da direita.
O comando (definido com -command {<comando a executar>}
no
momento de criação do widget ou pelo uso do comando .b1 config -command
...
) que nos devolve a lista de ítens selecionados no listbox da
esquerda é:
.lb1 curselection
Precisamos tomar cuidado com a ordem que isto é feito, pois o comando que nos devolve a lista de ítens selecionados, os devolve como uma lista de índices numérico, que serão modificados à medida que o listbox é modificado. Assim, devemos ordenar os índices, em ordem descrescente, para que as mudanças de posíção dos ítens não alterem os que ainda restam a serem movidos. Então, usamos o comando lsort, que ordena uma lista obedecendo vários critérios, com as opções para índices numéricos e em ordem decrescente:
set itens [lsort -integer -decreasing [.lb1 curselection]]
O restante da ação (comando) é imediata. Basta repetirmos o ato de movimentar
um ítem, para cada ítem da lista. Usamos a estrutura de controle foreach do
tcl para varrer a lista. Para inserir um ítem no listbox .lb2
, o
comando insert
, seguido do índice (posição) deste ítem e em
seguida o texto (conteúdo) do ítem. Para remover o ítem do listbox antigo
(.lb1)
, o comando delete
.
foreach i $itens { .lb2 insert 0 [.lb1 get $i] .lb1 delete $i }
Experimente selecionar ítens no listbox da esquerda, movendo-os para a direita
com a seta de cima. Para selecionar vários ao mesmo tempo, arraste o mouse com
o botão <1> pressionado. Para retirar um único ítem da seleção, segure a
tecla Control e clique no mouse normalmente, com esta tecla pressionada.
Depois mova de volta alguns ítens.
Experimente também rolar o conteúdo do listbox segurando o botão do meio (botão <2>) do mouse. Usuários de mouser "tipo Microsoft", com dois botões somente, terão que clicar os dois botões ao mesmo tempo, e certificar-se que o servidor X11 está com emulação de três botões habilitada. |
Como exercício, modifique esta interface, colocando um botão extra para
executar algum comando que use todos estes paràmetros (selecionados no listbox
da direita) e codifique-a com o visual tcl. Se voce quiser
executar algo com o shell do Unix, use o comando exec
como
prefixo do que você utilizaria normalmente.
O tk nos fornece um mecanismo simples para conectar scrollbars
a
outros widgets, uma vez que aqueles foram projetados exatamente para controlar
a visualização de widgets como canvas, text,
ou
listbox
. É mais fácil entender com um exemplo, (na realidade uma
receita bem simples): se tivermos um listbox .lb
e um
scrollbar .sb
que será usado para deslocar a parte visível do
listbox, faremos:
.lb config -yscrollcommand {.sb set} .sb config -command {.lb yview}
e de forma similar com a direção "x", substituindo yscrollcommand
por xscrollcommand
e yview
por
xview
. Evidentemente, o scrollbar
será criado com
-orient vertical
no primeiro caso e -orient
horizontal
neste último.
Modifique os dois listboxes
do exemplo visto acima para conter
scrollbars
ao lado de cada um (com -orient
vertical
) para poder rolar a lista de estados do Brasil.
O tcl permite-nos criar também procedures, como qualquer linguagem moderna, com argumentos passados por valor ou por referência, ou também com valor default para um argumento, e número de argumentos variável, determinado no momento da sua execução. Uma procedure pode também retornar um valor.
Declaramos uma procedure com o comando proc
, seguido do nome da
procedure, seguido da lista de arguentos, e seguido finalmente do corpo
(body)
da procedure.
No exemplo acima, podemos substituir os comandos atribuidos aos botões acima por uma procedure, que moverá os ítens selecionados de uma listbox para a outra. Os argumentos para esta procedure serão os nomes dos listboxes origem e destino, para generalizarmos:
proc moveSelection { orig dest } { set itens [lsort -integer -decreasing [.lb2 curselection]] foreach i $itens { $dest insert 0 [$orig get $i] $orig delete $i } }
onde orig
e dest
são os nomes dos widgets desejados.
Como estes são também comandos, sua invocação será feita pela subsituição
com $.
E assim, poderemos definir os botões acima como:
button .b1 -image right -command {moveSelection .lb1 .lb2} button .b2 -image left -command {moveSelection .lb2 .lb1}
Os programas criados pelo visual tcl definem uma procedure
main
e a executa logo após definir toda a interface. Este comando
é similar a um main na liguagem C, com argc
o número de
argumentos recebidos na linha de comando e argv
uma lista de
todos os parâmetros, exceto o argv0
, que é uma variável
adicional. Exemplo: no comando (dado na linha do shell) meuprog recife
pernambuco brasil
, teremos $argv0
contendo o nome
(completo, com path) do meuprog
, $argc
será 3
e lindex $argv 0
será recife
(o elemento de
índice 0 da lista; argv
conterá a lista recife pernambuco
brasil
. Além dessas variáveis pré-definidas, temos >env
,
um array indexado pelos nomes das variáveis do environment, o mesmo
acessível pelo shell do unix. Exemplo: $env(PATH)
será o nosso
PATH atual. Lembre-se que isso não é nenhuma particularidade do visual
tcl mas do próprio core do tcl. Qualquer programa terá estas
facilidades definidas.
Subsituindo um argumento na definição da procedure por uma (sub-)lista, podemos introduzir um default para o argumento não fornecido na chamada desta procedure. Por exemplo, a procedure seguinte imprime o nome dado como argumento entre separadores (separador default "/"):
proc entreseps { nome {sep /} } { puts $sep$nome$sep }
Executando entreseps nina
teremos a saida /nina/
,
enquanto que entreseps nina \"
teremos a saida
"nina"
. Observe que as aspas, por ser um caracter especial do
tcl, deverá ser quotada com a barra invertida.
Podemos processar também um número variável de argumentos se denominarmos o
último argumento na definição da procedure args
. Veja uma função
(procedure) que imprime cada argumento numerado numa linha diferente (o
puts
avança uma linha cada vez que é executado, a menos que
forneçamos a este a opção -nonewline
):
proc printargs { args } { for {set i 0} {[lindex $args $i] != ""} {incr i} { puts "$i: [lindex $args $i]" } }
Vá para o capítulo 1 e use o tclet no final deste para testar a funcão. Ou melhor, use uma console com o tclsh ou wish rodando, introduza esta procedure e teste-a fornecendo vários argumentos.