As três Fates
Steven Ferg (steve@ferg.org)
Traduzido e adaptado por J. Labaki
labaki@feis.unesp.br
Grupo Python
Departamento de Engenharia Mecânica
UNESP – Ilha Solteira
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
Índice
Sobre Pensando em Tkinter
3
Os programas
3
TT000 – Introdução
4
As quatro questões básicas da programação de GUIs
4
Alguns jargões da programação de GUIs
4
Sobre o Event Loop
5
TT010 – O programa em Tkinter mais simples possível: três linhas.
6
TT020 – Criando um objeto GUI e fazendo pack; containeres versus widgets.
7
Frames são elásticos
9
TT030 – Criando um Widget e colocando-o no frame.
9
TT035 – Usando a estrutura de classes no programa.
11
Por que estruturar sua aplicação como uma classe?
11
Quando introduzir a estrutura de classes
12
TT040 – Algumas formas diferentes de definir um widget.
13
TT050 – Empacotando.
14
Porque os botões apareceram verticalmente no último programa
14
Alguns termos técnicos – Orientação
15
TT060 – Fazendo Binding.
16
TT070 – Mexendo com foco e ligando eventos de teclado a widgets.
19
TT074 – Command Binding.
22
TT075 – Usando event binding e command binding juntos.
24
Para quais eventos serve command binding?
24
Usando event binding e command binding juntos
25
TT076 – Compartilhando informações entre alimentadores de eventos.
26
Compartilhando informações entre funções alimentadoras de eventos
26
Primeira solução – usar variáveis globais
27
Segunda solução – usar variáveis instanciadas
27
TT077 – Transmitindo argumentos para alimentadores de eventos I: O problema.
29
Características mais avançadas de command binding
29
TT078 – Transmitindo argumentos para alimentadores de eventos II: Usando Lambda.
31
TT079 – Transmitindo argumentos para alimentadores de eventos III: Usando Currying.
35
Sobre Curry
35
Curry – como usá-lo
36
Lambda versus Curry & event_lambda: qual devo usar?
38
TT080 – Opções de widget e configurações de pack
40
Três técnicas de controlar o layout de uma GUI
40
TT090 – Posicionando frames
43
TT095 – Métodos gerenciadores de janelas & controlando o tamanho de janelas com a opção
46
geometry.
TT100 – Opções de pack: side, expand, fill e anchor.
49
Um jeito prático de encontrar erros
50
2
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
Sobre Pensando em Tkinter
Tenho tentado aprender sozinho Tkinter por vários livros, e tenho encontrado mais
dificuldade do que poderia pensar.
O problema é que os autores desses livros já começam dizendo tudo sobre os widgets
disponíveis em Tkinter, mas nunca dão uma parada para explicar os conceitos básicos. Eles
não explicam como “pensar em Tkinter”. Então achei que deveria tentar escrever um livro
do tipo que eu mesmo estou procurando. Ou ao menos rascunhar esse tipo de livro.
Pensando em Tkinter consiste de pequenos programas que começam a explicar como
pensar em Tkinter. Nestes, não me preocupo em catalogar todos os tipos de widgets,
atributos e métodos disponíveis em Tkinter, somente em dar um empurrãozinho na direção
dos conceitos básicos do assunto.
Estes programas não têm intenção de introduzir todos os aspectos da programação de
Tkinter. Para este fim, sugiro que leia “An Introduction to Tkinter”, de Frederik Lundh e
“Tkinter, GUI Programming with Python”, da New México Tech Computer Center.
Acima de tudo, quero enfatizar que “Practical Programming in Tcl and Tk” de Brend
Welch é absolutamente essencial para trabalhar com Tk e Tkinter. Arranje esse livro!
Note que você não deve rodar estes programar usando o IDLE. O IDLE é por si só uma
aplicação de Tkinter; possui seu próprio “mainloop” que entrará em conflito com o
mainloop incluído nestes programas. Se você insiste em ver e rodar estes programas usando
IDLE, então – para cada programa – deverá apagar a linha correspondente ao mainloop
antes de rodá-lo.
Este material tem sido substancialmente melhorado pelo feedback dos entusiastas e
comunidade pythoniana. Meu grande “Obrigado!” a Alan Colburn, Jeff Epler, Greg Ewing,
Tom Good, Steve Holden, Joseph Knapka, Gerrit Müller, Russel Owen, e Chad Netzer.
Obrigado a Terry Carroll por recolher e organizar esse material.
Finalmente, se você é novo na programação orientada a eventos (que Tkinter requer), deve
dar uma olhada neste assunto antes.
Os Programas
Você deve baixar o arquivo zip que contém todos os programas. Pode ser através do
seguinte endereço:
http://geocities.yahoo.com.br/grupopython/pensando_em_tkinter.zip
O pacote contém os programas de “Pensando em Tkinter”. Para instalar estes arquivos,
simplesmente descompacte o pacote de arquivos em um diretório de sua escolha.
3
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
TT000 – Introdução.
Eis alguns programas que começarão a explicar como pensar em Tkinter. Neles, como já
disse, não atento para todos os tipos de widgets, atributos e métodos disponíveis em
Tkinter, tampouco tento dar uma introdução detalhada sobre Tkinter, somente tento iniciar
você no caminho para entender os seus conceitos básicos.
No decorrer do programa de ensino, a discussão é dedicada exclusivamente ao gerenciador
de geometria pack. Não falaremos sobre os gerenciadores grid ou place.
As quatro questões básicas na programação de GUIs.
Quando você desenvolve uma interface com o usuário (IU) há um conjunto padrão de
questões que você deve satisfazer.
1) Você deve especificar como você quer que a IU se pareça. Isto é, você precisa
escrever um código que determina o que o usuário verá na tela do computador;
2) Você deve decidir o que quer que a IU faça. Isto é, você deve escrever
procedimentos que satisfaçam as necessidades do programa;
3) Você precisa associar o parecer com o fazer. Isto é, você deve escrever um código
que associa as coisas que o usuário vê na tela com os procedimentos que você
escreveu para desempenhar os papéis requeridos pelo programa;
4) Finalmente, você deve escrever um código que senta e espera pela entrada do
usuário.
Alguns jargões da programação de GUIs.
A programação GUI (Graphic User Interface – Interface Gráfica com o Usuário) tem alguns
jargões especiais associados às suas questões básicas.
1) Nós especificamos como queremos que um GUI se pareça descrevendo os “widgets”
que queremos exibir, e suas relações especiais (por exemplo, o quanto um widgets
está abaixo ou acima, ou à direita ou à esquerda de outros widgets). A palavra
“widget” é um termo sem tradução que designa “componentes de interface gráfica
com o usuário” de um modo geral. Widgets inclui elementos como janelas, botões,
menus e itens de menus, ícones, listas rolantes, barras de rolagem, etc.
2) Os procedimentos que executam as tarefas dos GUIs são chamados “event handler”.
“Events” são formas de entrada de dados como cliques de mouse ou digitação no
teclado. Esses procedimentos são chamados “handlers” (alimentadores) porque eles
“alimentam” (isto é, respondem a) estes eventos.
3) A associação de um event handler a um widget é chamada “binding”. De modo
geral o processo de binding envolve a associação entre três coisas diferentes:
4
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
a. Um tipo de evento (por exemplo, um clique no botão esquerdo do mouse, ou
pressionar a tecla ENTER),
b. Um widget (por exemplo, um botão) e
c. Um procedimento event handler.
Por exemplo, nós precisamos fazer binding (a) num clique com o botão esquerdo do
mouse no (b) botão “FECHAR” na tela para (c) executar o procedimento
“fechePrograma”, que fechará a janela e desligará o programa.
4) O código que senta e espera pela entrada de dados é chamada de “event loop”.
Sobre o Event Loop
Se você tem visto filmes, sabe que toda cidadezinha tem uma vovó que perde todo seu
tempo debruçada na janela, só olhando. Ela vê tudo que acontece na vizinhança. Uma parte
disso não tem graça, é claro – só pessoas subindo e descendo a rua. Mas a outra é
interessante – como uma bela briga entre os pombinhos recém-casados do outro lado da
rua. Quando algo interessante acontece, essa vovozinha cão-de-guarda imediatamente corre
para o telefone contar tudo à polícia da vizinhança.
O Event Loop é algo como essa vovozinha: gasta todo seu tempo esperando que eventos
aconteçam. Muitos dos eventos não têm importância (como clicar num ponto neutro da
janela), e quando os vê, não faz nada. Mas quando vê alguma coisa interessante – um
evento que ele sabe, por meio de um binding de event handler, que é interessante (como um
clique num dos botões da janela) – então imediatamente contata os event handler e faz com
que saibam que o evento aconteceu.
Comportamento do Programa
Este programa facilita a você o entendimento da programação de interfaces com o usuário
mostrando como estes conceitos básicos são implementados em um programa muito
simples. Este programa não usa Tkinter ou qualquer forma de programação GUI, somente
coloca um menu e um console, e recebe caracteres digitados no teclado como entrada.
Assim, como você pode ver, ele satisfaz as quatro questões básicas da programação de
interfaces com o usuário.
#Questão 2: Define os procedimentos de event handler
def handle_A():
print "Wrong! Try again!"
def handle_B():
print "Absolutely right! Trillium is a kind of flower!"
def handle_C():
print "Wrong! Try again!"
#Questão 1: Define a aparência da tela
print "\n"*100 # clear the screen
print " VERY CHALLENGING GUESSING GAME"
print "========================================================"
5
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
print "Press the letter of your answer, then the ENTER key."
print
print " A. Animal"
print " B. Vegetable"
print " C. Mineral"
print
print " X. Exit from this program"
print
print "========================================================"
print "What kind of thing is 'Trillium'?"
#Questão 4: O Event Loop. Loop eterno, esperando que algo aconteça.
while 1:
# Observamos o próximo evento
answer = raw_input().upper()
# --------------------------------------------------------------
# Questão 3: Associamos os eventos de teclado que nos interessam
# com seus event handlers. Uma forma simples de binding.
# --------------------------------------------------------------
if answer == "A": handle_A()
if answer == "B": handle_B()
if answer == "C": handle_C()
if answer == "X":
# clear the screen and exit the event loop
print "\n"*100
break
#Perceba que quaisquer outros eventos não interessam, por isso são
ignorados.
TT010 – O programa em Tkinter mais simples possível: três linhas.
Das quatro questões básicas na programação de GUIs que nós vimos no último programa,
este programa cumpre somente uma – ele roda o event loop.
(1)
A primeira linha importa o módulo Tkinter e deixa-o disponível para uso. Perceba que a
forma de importar (“from Tkinter import *”) significa que nós não queremos ter que
usar a forma “Tkinter.” para especificar nada que quisermos utilizar.
(2)
A segunda linha cria uma janela toplevel (que pode ou não se tornar visível). Tecnicamente,
o que esta linha faz é criar uma instância da classe “Tkinter.Tk”.
Esta janela toplevel é o componente GUI de mais alto nível1 de qualquer aplicação de
Tkinter. Por convenção, esta janela é normalmente chamada de “raiz”.
(3)
A terceira linha executa o método mainloop (isso é, o event loop) deste objeto raiz. Assim
que roda, o mainloop espera que eventos aconteçam no objeto raiz. Se um evento ocorre,
então ele é alimentado (o event handler é executado) e o loop continua rodando, esperando
1 Entenda por “de alto nível” a aplicação que tem mais relação com o usuário que com o código (N do T).
6
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
pelo próximo evento, ou até que aconteça um evento que “destrua” a raiz. Um evento
destruidor pode ser o fechamento da janela pelo botão X de fechamento. Quando a raiz é
destruída, a janela é fechada e o event loop cancelado.
Comportamento do programa
Ao rodar este programa, você verá (graças ao Tk) a janela toplevel automaticamente com os
widgets para minimizar, maximizar e fechar a janela. Tente usá-los – você verá que eles
realmente funcionam.
Clicando no widget “fechar” (o X em uma caixa, do lado direito da barra de título) será
gerado um evento destruidor terminando o event loop principal, que no caso deste programa
é mainloop. E desde que não haja mais nada depois da linha “root.mainloop()”, como
neste caso, o programa não faz mais nada e se encerra.
from Tkinter import * ###(1)
root = Tk() ###(2)
root.mainloop() ###(3)
TT020 – Criando um objeto GUI e fazendo pack; containeres versus
widgets.
Agora daremos uma pincelada em outra das quatro questões básicas da programação GUI –
especificar como a GUI deverá parecer.
Neste programa, introduzimos três dos maiores conceitos da programação em Tkinter:
criar um objeto GUI e associá-lo com seus mestres;
pack e
container versus widget.
De agora em diante, distinguiremos os componentes entre containeres e um widgets. Como
usarei sempre estes termos, um widget é um componente GUI que (geralmente) é visível e
faz coisas. Já um container é simplesmente um container – uma cesta, como queira – dentro
do qual dispõem-se os widgets.
Tkinter oferece vários tipos de containeres. “Canvas” é um container para aplicações de
desenho, e o container mais freqüentemente utilizado é o “Frame”.
Frames são oferecidos pelo Tkinter como uma classe chamada “Frame”. Uma expressão
como:
Frame(meuMestre)
7
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
cria uma instância da classe Frame (isto é, cria um frame), e associa a instância ao seu
mestre, meuMestre. Outra maneira de ver isso é como uma expressão que adiciona um
frame “escravo” ao componente meuMestre.
Então, neste programa (linha 1),
myContainer1 = Frame(myParent)
cria um frame cujo mestre é myParent (isto é, a raiz), e dá a ele o nome de
“myContainer1”. Resumindo, ele cria um container dentro do qual podemos agora colocar
widgets. (Nós não colocaremos nenhum widget neste programa, somente posteriormente).
Perceba que a relação mestre/escravo aqui é somente lógica, não tem nada de visual. Esta
relação existe para otimizar eventos do tipo destrutivo – isso porque quando um
componente mestre (como root) é destruído, o mestre sabe quem são seus escravos, e pode
destruí-los antes de se destruir.
(2)
A próxima linha define o gerenciador de geometria “pack” para administrar myContainer1.
myContainer1.pack()
Simplesmente designado, “pack” é um método que transforma em visuais as relações entre
os componentes GUI e seus mestres. Se você não definir o componente pack ou outro
gerenciador de geometria, nunca verá a GUI.
Um gerenciador de geometria é essencialmente um API – um meio de dizer ao Tkinter
como você quer que containeres e widgets se apresentem visualmente. Tkinter oferece três
gerenciadores para esta finalidade: pack, grid e place. Pack e grid são os mais usados por
serem mais simples. Todos os exemplos em “Pensando em Tkinter” usam pack como
gerenciador de geometria.
O esquema padrão básico da programação em Tkinter, que veremos ainda diversas vezes,
funciona mais ou menos assim:
uma instância (de um widget ou um container) é criada, e associada ao seu
mestre;
a instância é administrada por um gerenciador de geometria.
Comportamento do programa
Quando você roda este programa, ele se parecerá muito com seu antecessor, exceto pelo
tamanho. Isso é porque...
8
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
Frames são elásticos
Um frame é basicamente um container. O interior de um container – o “espaço” existente
dentro dele – é chamado “cavidade”, um termo técnico que Tkinter herdou de Tk. Essa
cavidade é extensível (ou elástica) como uma borracha. A menos que você especifique um
tamanho máximo ou mínimo para o frame, a cavidade será esticada ou comprimida até
acomodar qualquer coisa que o frame contiver.
No programa anterior, por não termos colocado nada dentro dela, a raiz mostrou a si mesma
na tela com seu tamanho padrão, mas neste programa, nós preenchemos sua cavidade com o
myContainer1. Agora, a raiz se estica para acomodar o tamanho de myContainer1, mas
como não colocamos nenhum widget neste frame, nem especificamos um tamanho mínimo
para ele, a cavidade da root se encolhe até o limite. Por isso não há nada para ser visto
abaixo da barra de título desse programa.
Nos próximos programas, colocaremos widgets e outros containeres dentro do Container1,
e você verá como ele se arranja para acomodá-los.
from Tkinter import *
root = Tk()
myContainer1 = Frame(root) ###(1)
myContainer1.pack() ###(2)
root.mainloop()
TT030 – Criando um Widget e colocando-o no frame.
Neste programa, nós criamos nosso primeiro widget e o colocamos dentro de
myContainer1.
(1)
O Widget será um botão – isto é, ele será uma instância da classe “Button” de Tkinter. A
linha:
Button1=Button(myContainer1)
cria o botão, dando-o o nome de “button1”, e associa-o ao seu mestre, o objeto container
chamado myContainer1.
(2)(3)
Os widgets tem muitos atributos, todos disponíveis no dicionário do namespace local. O
widget “Button” tem atributos para controlar seu tamanho, sua cor de fundo e de fonte, seu
texto, como suas bordas se parecerão, etc. Neste exemplo, nós iremos ajustar somente dois
9
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
S T E V E N F E R G
P E N S A N D O E M T K I N T E R
atributos de button: a cor de fundo e o texto. Faremos isso mudando os valores do seu
dicionário referentes às chaves “text” e “background”.
button1["text"] = "Hello, World! "
button1["background"] = "green"
(4)
E, é claro, nós fazemos pack no botão button1.
button1.pack()
Comportamento do programa
Quando você rodar este programa, deverá ver que o Container1 agora contém um botão
verde com o texto “Hello, World!”. Quando você clica nele não acontece nada, porque nós
ainda não especificamos o que queremos que aconteça quando o botão for clicado, se bem
que o faremos mais tarde.
Por ora, você deverá clicar no botão X da barra de título para fechá-lo, como antes.
from Tkinter import *
root = Tk()
myContainer1 = Frame(root)
myContainer1.pack()
button1 = Button(myContainer1) ### (1)
button1["text"]= "Hello, World!" ### (2)
button1["background"] = "green" ### (3)
button1.pack()
### (4)
root.mainloop()
TT035 – Usando a estrutura de classes no programa.
Neste programa, introduziremos o conceito de aplicações de Tkinter estruturadas como
classes.
Nele, criamos uma classe chamada MyApp e transcrevemos alguns códigos dos programas
anteriores para dentro de seu método construtor (__init__). Nesta versão reestruturada do
programa, fazemos 3 coisas diferentes:
(1)
Em nosso código, designamos uma classe (MyApp) que define como queremos que a GUI
se pareça e que tipo de coisa queremos fazer com isso. Todo este código é inserido no
método construtor da classe.
10
G R U P O P Y T H O N – U N E S P – I L H A S O L T E I R A
Add New Comment