![]() |
Tcl/Tk
Curso On-Line de Programação |
Associando eventos
Eventos são ações realizadas pelo usuário e interceptadas pelo programa. Em Tk eventos são chamados binds( aderências ). Os binds são usados para verificar as teclas pressionadas pelo usuário e os movimentos do ponteiro do mouse.
Também podemos simular eventos, de modo que o programa se comporte como se o usuário tivesse realizado uma determinada ação.
O uso mais frequente de binds em programas comerciais é a verificação dos dados digitados pelo usuário, ou para criar teclas de atalho para botões e menus.
A seguir estudaremos os comandos usados
para conectar eventos aos widgets Tk e para simulá-los, quando for
necessário.
| Comando | Descrição |
| bind tag | Retorna uma lista de todas as sequências, para as quais existem binds correspondentes à tag dada. |
| bind tag sequência | Retorna o script correspondente à sequência e à tag dadas. |
| bind tag sequência script | Adere o script à sequência para a tag dada. Se script for uma string vazia, a bind é apagada. Se o primeiro caractere do script for +, então o script será anexado ao script atualmente associado à sequência e à tag dadas. |
| bindtags janela [lista_de_tags] | Ajusta a ordem de precedência das tags para a janela de acordo com a lista dada. Se a lista estiver vazia, a ordem será ajustada para a ordem padrão. |
| event add <<virtual>> sequência sequência... | Configura para que o evento virtual <<virtual>> seja disparado, se qualquer das sequências dadas ocorrer. |
| event delete <<virtual>> [sequência...] | Apaga a sequência dada, ou todas caso nenhuma sequência seja especificada, da lista de sequências que disparam o evento virtual dado. |
| event generate janela evento [-when quando] [opção valor...] | Provoca um evento, na janela dada, como se ele tivesse sido gerado pelo sistema. Várias opções estão disponíveis e serão listadas a seguir. A opção -when indica quando o evento deve ser disparado: now( imediatamente ), tail( coloca no final da fila de eventos ), head( coloca no início da fila de eventos ) ou mark( como head, mas coloca entre os eventos gerados anteriormente ). |
| event info <<virtual>> | Retorna a lista de sequências que disparam o evento virtual. Se o evento não for especificado, retorna a lista de todos os eventos virtuais definidos. |
O argumento sequencia é uma lista de um ou mais tipos de evento. Um evento pode ser desde um caractere ASCII a uma string na forma <modificador-modificador-tipo-detalhe>, ou <<nome>>, para um evento virtual.
Veja a lista de modificadores possíveis: Any, Control, Shift, Lock, Double, Triple, Button1, Button2, Button3, Button4, Button5, B1, B2, B3, B4, B5, Meta, M, Mod1, Mod2, Mod3, Mod4, Mod5, M1, M2, M3, M4, M5, Alt.
Os tipos de eventos possíveis são: Activate, ButtonPress, Button, ButtonRelease, Circulate, Colormap, Configure, Deactivate, Destroy, Enter, Expose, FocusIn, FocusOut, Gravity, KeyPress, Key, KeyRelease, Motion, Leave, Map, Property, Reparent, Unmap, Visibility.
Os detalhes suportados são: para botões, um número de 1 a 5, para teclas, um símbolo definido em /usr/include/X11/keysymdef.
As tags podem ser: uma janela interna, e se aplicará somente a esta janela, um toplevel, e se aplicará a todas as suas janelas internas, uma classe de janelas, e se aplicará a todos os widgets desta classe, ou all e se aplicará a todas as janelas.
Dentro do script de um evento, você
pode fazer referência à tecla pressionada, à janela
onde o evento ocorreu, às coordenadas do mouse no momento em que
o evento ocorreu etc. A seguir são apresentadas Os códigos,
que atuam como se fossem variáveis, definidas por Tk para referenciar
cada uma dessas informações:
| Variável | Descrição |
| %% | Um sinal %. |
| %# | O campo serial do último evento. |
| %a | O campo acima. |
| %b | O número do botão. |
| %c | O campo contador. |
| %d | O campo detalhe. |
| %f | O campo focus. |
| %h | O campo altura. |
| %k | O campo código da tecla. |
| %m | O campo modo. |
| %o | O campo override_redirect. |
| %p | O campo place. |
| %s | O campo estado. |
| %t | O campo time. |
| %w | O campo largura. |
| %x | O campo x. |
| %y | O campo y. |
| %A | O caractere ASCII. |
| %B | O campo largura da borda. |
| %E | O campo send_event. |
| %K | O símbolo da tecla pressionada como texto. |
| %N | O símbolo da tecla pressionada como um número decimal. |
| %R | A janela principal( root ). |
| %S | Identificador sub_window. |
| %T | O campo tipo. |
| %W | O nome( caminho ) da janela onde o evento ocorreu. |
| %X | O campo x_root. |
| %Y | O campo y_root. |
Os eventos suportam as seguintes opções:
| Opção | Código | Evento válido |
| -above janela | %a | Configure |
| -borderwidth largura | %B | Configure |
| -button número | %b | ButtonPress, ButtonRelease |
| -count número | %c | Expose |
| -detail detalhe | %d | Enter, Leave, Focus |
| -focus booleano | %f | Enter, Leave |
| -height altura | %h | Configure |
| -keycode número | %k | KeyPress, KeyRelease |
| -keysym nome | %K | KeyPress, KeyRelease |
| -mode modo | %m | Enter, Leave, Focus |
| -override booleano | %o | Map, Reparent, Configure |
| -place onde | %p | Circulate |
| -root janela | %R | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion |
| -rootx coordenada | %X | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion |
| -rooty coordenada | %Y | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion |
| -sendevent booleano | %E | Todos os eventos |
| -serial número | %# | Todos os eventos |
| -state estado | %s | Todos os eventos |
| -subwindow janela | %S | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion |
| -time inteiro | %t | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion, Property |
| -x coordenada | %x | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion, Expose, Configure, Gravity, Reparent |
| -y coordenada | %y | KeyPress, KeyRelease, ButtonPress, ButtonRelease, Enter, Leave, Motion, Expose, Configure, Gravity, Reparent |
Associando teclas de atalho
Normalmente associamos teclas de atalho a botões e menus. Para indicar a tecla de atalho em um botão sublinhamos a tecla correspondente através da opção -underline:
# Cria uma janela
toplevel .t
# Cria um botao com a primeira letra do rotulo sublinhada
button .t.b -text OK -underline 0 -command {destroy .t}
# Dispoe o botao na janela
pack .t.b
# Configura o evento pressionar as teclas Alt( esquerda ) + O( minusculo ) para que invoque o comando default do botao
bind .t <Key-Alt_L><Key-o> {.t.b invoke}
O exemplo acima configura a tecla de atalho
ALT+O para o botao OK.
Para indicar a tecla de atalho para um menu devemos utilizar a opção -accelerator do menu:
# Cria a janela
toplevel .w1
wm protocol .w1 WM_DELETE_WINDOW {exit}
wm title .w1 "HTML Browser"
wm resizable .w1 1 1
# Centraliza a janela na tela
set x [expr {([winfo screenwidth .w1] - 640)/2}]
set y [expr {([winfo screenheight .w1] - 480)/2}]
# # Cria os paineis #
# Painel principal frame .w1.fr0 -borderwidth 2 -relief raised # Painel do menu frame .w1.fr0.fr1 -borderwidth 2 -relief raised # Painel da barra de ferramentas frame .w1.fr0.fr2 -borderwidth 2 -relief raised # Painel da barra de navegacao frame .w1.fr0.fr3 -borderwidth 2 -relief raised # Painel da janela do browser frame .w1.fr0.fr4 -borderwidth 2 # Painel da barra de status frame .w1.fr0.fr5 -borderwidth 2 -relief raised
# # Cria os componentes dos paineis #
# Cria os menus menubutton .w1.fr0.fr1.file -text "Arquivo" -underline 0 -menu .w1.fr0.fr1.file.menu menubutton .w1.fr0.fr1.edit -text "Editar" -underline 0 -menu .w1.fr0.fr1.edit.menu menubutton .w1.fr0.fr1.options -text "Opcoes" -underline 0 -menu .w1.fr0.fr1.options.menu menubutton .w1.fr0.fr1.help -text "Ajuda" -underline 1 -menu .w1.fr0.fr1.help.menu
# Menu Arquivo
menu .w1.fr0.fr1.file.menu
.w1.fr0.fr1.file.menu add command -label "Abrir" -accelerator "Ctrl+O" -command {bell}
.w1.fr0.fr1.file.menu add separator
.w1.fr0.fr1.file.menu add command -label "Sair" -accelerator "Ctrl+R" -command {exit}
# Menu Editar
menu .w1.fr0.fr1.edit.menu
.w1.fr0.fr1.edit.menu add command -label "Procurar" -accelerator "Ctrl+F" -command {bell}
# Menu Opcoes menu .w1.fr0.fr1.options.menu .w1.fr0.fr1.options.menu add cascade -label "Tamanho da fonte" -menu .w1.fr0.fr1.options.menu.font .w1.fr0.fr1.options.menu add cascade -label "Nivel de indentacao" -menu .w1.fr0.fr1.options.menu.indent
# Menu Ajuda
menu .w1.fr0.fr1.help.menu
.w1.fr0.fr1.help.menu add command -label "Conteudo" -accelerator "F1" -command {bell}
.w1.fr0.fr1.help.menu add separator
.w1.fr0.fr1.help.menu add command -label "Sobre" -command {bell}
menu .w1.fr0.fr1.options.menu.font
.w1.fr0.fr1.options.menu.font add radiobutton -label "Pequena" -value 0 -variable Size -command {bell}
.w1.fr0.fr1.options.menu.font add radiobutton -label "Media" -value 4 -variable Size -command {bell}
.w1.fr0.fr1.options.menu.font add radiobutton -label "Grande" -value 12 -variable Size -command {bell}
menu .w1.fr0.fr1.options.menu.indent
.w1.fr0.fr1.options.menu.indent add radiobutton -label "Pequena" -value 0.6 -variable Indent -command {bell}
.w1.fr0.fr1.options.menu.indent add radiobutton -label "Media" -value 1.2 -variable Indent -command {bell}
.w1.fr0.fr1.options.menu.indent add radiobutton -label "Grande" -value 2.4 -variable Indent -command {bell}
# # Instala os componentes #
# Instala os paineis pack .w1.fr0 -expand 1 -fill both pack .w1.fr0.fr1 .w1.fr0.fr2 .w1.fr0.fr3 -fill x pack .w1.fr0.fr4 -expand 1 -fill both pack .w1.fr0.fr5 -fill x # Instala os componentes da barra de menu pack .w1.fr0.fr1.file .w1.fr0.fr1.edit .w1.fr0.fr1.options -side left pack .w1.fr0.fr1.help -side right
# Redimensiona a janela wm geometry .w1 640x480+$x+$y
# Configura a tecla de atalho para o menu Arquivo->Sair como sendo Ctrl( esquerdo ) + R( minusculo )
bind .w1 <Key-Control_L><r> {exit}
O fragmento de código acima,
adaptado do código fonte do meu browser TkShip, cria uma janela
com uma barra de menu e configura a tecla de atalho do menu Arquivo->Sair
para CTRL+R.
Copie e cole o código acima na linha
de comandos do wish e veja como funciona.
Validando a entrada do usuário
Validar a entrada digitada pelo usuário é uma dos usos mais importantes para os binds. Tk 8.3 ou superior inclui o suporte a validação de dados digitados no widget entry, entretanto, versões mais antigas do Tk, e que acompanham a maioria das distribuições do Linux, só podem validar a entrada digitada através de binds. De fato, tudo o que as opções de validação do Tk 8.3 fazem é configurar binds para o widget entry, como faremos nesta seção.
Mas antes de prosseguir-mos, muitas pessoas me perguntam como trocar o comportamento default do X-Window/Windows de TAB para ENTER, para mudar o foco entre os widgets de uma janela. O fragmento de código a seguir fará exatamente isso:
# Configura a tecla ENTER para que realize a mudanca de foco entre os widgets de uma janela
bind Toplevel all <Key-Return> {focus [tk_focusNext %W]}
Agora vejamos como configurar os binds
de um widget entry para que seja realizada a validação dos
dados:
# Cria a janela
toplevel .t
entry .t.e -justify right
pack .t.e -side left -expand 1 -fill x
# Configura o tipo de dado que pode ser digitado
# Esta forma nao e elegante, voce deve evita-la
# bind .t.e <Key> {
# if {((%N < 44) || (%N > 57) || ([string length [%W get]] >= 10)) && ((%N >= 32) && (%N <= 128))} {
# bell
# break
# }
# }
# Esta e a forma elegante de configurar a validacao dos dados
# A parte ([regexp -nocase {[0-9]} %A] == 0) determina que somente valores numericos podem ser aceitos
# A parte ([string length [%W get]] >= 10) determina que somente 10 digitos devem ser aceitos
# A parte ((%N >= 32) && (%N <= 128)) e necessaria para permitir os caracteres ASCII de controle como
# DELETE e BACKSPACE
bind .t.e <Key> {
if {(([regexp -nocase {[0-9]} %A] == 0) || ([string length [%W get]] >= 10)) && ((%N >= 32) && (%N <= 128))} {
bell
break
} }
# Faz com que todo o texto dentro do widget seja selecionado, quando ele receber o foco
bind .t.e <FocusIn> {
.t.e selection range 0 end
}
Agora se desejar-mos que os dados sejam
formatados após a digitação, deveremos criar uma função
que formate o texto para nós. Como a função abaixo,
que formata um numero na forma #.##, útil para valores monetários:
# float2cur valor
# Formata um valor numerico para a forma #.##
proc float2cur {{valor 0.00}} {
set vetor {}
set vetor [split $valor .]
set p1 ""
set p2 ""
set val ""
if {[llength $vetor] == 2} {
if {[lindex $vetor 0] != ""} {
set p1 [lindex $vetor 0]
} else {
set p1 "0"
}
if {[lindex $vetor 1] != ""} {
set x1 [format {%1$-2s} [lindex $vetor 1]]
regsub " " $x1 0 x1
regsub " " $x1 0 x1
set p2 $x1
} else {
set p2 "00"
}
} else {
if {[lindex $vetor 0] != ""} {
set p1 [lindex $vetor 0]
} else {
set p1 "0"
}
set p2 "00"
}
if {[string length $p2] > 2} {
set x2 [string range $p2 0 1]
if {[string index $p2 2] > 5} {
if {$x2 < 99} {
if {[string index $x2 0] == 0} {
set x2 [string index $x2 1]
incr x2
set x2 [format {%1$02u} $x2]
} else {
incr x2
}
} else {
set x2 "00"
incr p1
}
}
set p2 $x2
}
append val $p1 . $p2
return $val
}
# Cria a janela
toplevel .t
entry .t.e -justify right
pack .t.e -side left -expand 1 -fill x
# Configura o tipo de dado que pode ser digitado
bind .t.e <Key> {
if {(([regexp -nocase {[0-9]} %A] == 0) || ([string length [%W get]] >= 10)) && ((%N >= 32) && (%N <= 128))} {
bell
break
} }
# Faz com que todo o texto dentro do widget seja selecionado, quando ele receber o foco
bind .t.e <FocusIn> {
.t.e selection range 0 end
}
# Configura para que a informacao digitada seja formatada quando o widget perder o foco
bind .t.e <FocusOut> {
set temp [float2cur [%W get]] %W delete 0 end %W insert 0 $temp
}
Experimente o fragmento de código
acima copiando-o e colando-o na linha de comandos do wish. Os dados serão
formatados quando o widget entry perder o foco.
Para uma descrição detalhada de todos os comandos disponíveis em Tk, consulte a documentação on-line, ou o Tcl/Tk Reference Guide, ou ainda o Tcl/Tk Electronic Reference.
Para maiores informações envie e-mail para info@souzamonteiro.com.
| http://www.souzamonteiro.com |
Copyright(C) 2000 by Roberto Luiz Souza Monteiro