Nos artigos anteriores sobre PyGTK, eu apresentei quatro widgets básicos:
- gtk.Window – uma janela
- gtk.VBox – um container para acomodar os widgets
- gtk.Button – botão
- gtk.Label – uma etiqueta para texto
Muitos outros widgets básicos não foram nem mencionados, como o gtk.Entry (caixa de texto), gtk.TreeView (lista em árvore), gtk.Toolbar (barra de ferramentas), entre outros.
Acontece que não vou mostrar nenhum deles aqui ainda.
Vamos falar de um componente que é menos usado nas aplicações em geral mas é muito útil. É o gtk.DrawingArea, Uma simples janela X onde podemos desenhar qualquer coisa, inclusive quadrados verdes com borda preta, de 50×50 pixels. E é exatamente isso que vamos fazer aqui.
Vamos construir, passo a passo, uma janela que contem uma área de desenho (DrawingArea) e um botão. Vamos chamar a área de desenho de tela.
A cada clique de mouse na tela, um quadrado verde é desenhado, tendo como centro o ponto clicado.
O botão vai limpar a tela.
Se você ainda não sabe como criar uma janela em PyGTK, leia primeiro esses dois pequenos artigos:
Criando uma simples janela com pygtk
Criando uma simples janela em pygtk – parte II
O grande astro da noite é a gtk.DrawingArea. Então vamos criar nossa tela:
tela=gtk.DrawingArea()
Como deveríamos saber, interfaces gráficas trabalham com eventos, como cliques em um botão, cliques e movimentos de mouse, teclas pressionadas, janelas arrastadas, minimizadas, escondidas por outras, etc. O usuário simplesmente dispara os eventos, o programador cuida de criar respostas a eles. Para uma DrawingArea um evento importante é o expose-event, disparado quando a tela é reexibida. Se a tela estava oculta, quando ela volta a aparecer precisa ser redesenhada, então vamos conectar o expose-event à função que vai desenhar os nossos preciosos quadrados verdes:
tela.connect('expose-event',desenha)
Outro evento importante para o nosso programa é o button-press-event, disparado quando você clica na tela com o mouse; mas este evento não está configurado, então vamos adicioná-lo à nossa tela, e então fazer a conexão com a função que vai criar nossos imprescindíveis quadrados verdes:
tela.add_events( gtk.gdk.BUTTON_PRESS_MASK )
tela.connect('button-press-event',cria_quadrado)
Não nos esqueçamos do objetivo deste programa: criar quadrados verdes. Os quadrados serão armazenados em uma lista. Listas são um tipo de dados que o Python nos provê. Criaremos a lista de quadrados:
quadrados=[]
Agora a coisa começa a ficar mais interessante. Dê uma olhada na função criar_quadrado(), que será executada a cada clique na tela:
def cria_quadrado(tela,evento):
global quadrados
coor=evento.get_coords()
x=coor[0]
y=coor[1]
novo_quadrado=[ x-25 , y-25 , 50 , 50 ]
quadrados.append(novo_quadrado)
desenha(tela,None)
A função recebe dois parâmetros: a tela onde ocorreu o evento, e o evento propriamente dito.
A segunda linha da função declara como global a lista de quadrados, ou seja, um objeto criado fora da função pode ser acessado de dentro dela sem ter sido passado como parâmetro.
A terceira linha pega as coordenadas do evento. O ponto exato onde ocorreu o clique. O método get_coords() retorna uma tupla com as coordenadas X e Y. Assim: (X,Y).
A quarta e quinta linhas criam duas variáveis para conter os valores da tupla.
A sexta linha finalmente cria o nosso quadrado (não desenha, só cria) e a sétima o adiciona à lista de quadrados. O quadrado, então, nada mais é que uma outra lista contendo as coordenadas de inicio, a largura e a altura.
Vamos analisar melhor o quadrado criado:
x-25 : é o primeiro item da lista. Indica a coordenada X do canto superior esquerdo do quadrado.
y-25: é o segundo item da lista e indica a coordenada Y do canto superior esquerdo do quadrado.
Os valores x e y vieram do evento de mouse. Subtraímos 25 (alguém reparou que 25 é metade de 50?) de cada para que o ponto clicado fosse o centro do quadrado.
Em uma DrawingArea, as coordenadas são orientadas de cima para baixo e da esquerda para a direita.
50: terceiro e quarto itens da lista; respectivamente altura e largura do quadrado.
A oitava linha da função ‘cria_quadrado’ chama a função ‘desenha’. A tela é passada como parâmetro. None é o segundo parâmetro, e só está aí porque a função pede um segundo parâmetro (ela também é disparada quando ocorre o expose-event).
Já sabemos como criar os quadrados na memória. O próximo passo é desenhá-los na tela:
def desenha( tela , evento ):
global quadrados
gc=tela.get_style().fg_gc[gtk.STATE_NORMAL]
verde=gtk.gdk.Color(0,48255,0,0)
preto=gtk.gdk.Color(0,0,0,0)
fundo=gtk.gdk.Color(65535,65535,65535,0)
#pintando o fundo da nossa tela
gc.set_rgb_fg_color(fundo)
tela.window.draw_rectangle(gc,True,0,0,800,600 )
for q in quadrados:
gc.set_rgb_fg_color(verde)
tela.window.draw_rectangle(gc,True,q[0],q[1],q[2],q[3])
gc.set_rgb_fg_color(preto)
tela.window.draw_rectangle(gc,False,q[0],q[1],q[2],q[3])
Dissecando a função:
Aqui vamos usar a lista de quadrados, que foi criada fora do contexto desta função e é modificada por outra função. Por isso o global quadrados.
Precisamos também criar um graphics context (gc):
gc=tela.get_style().fg_gc[gtk.STATE_NORMAL]
Um graphics context armazena informações como cor de fundo, de primeiro plano e espessura da linha de desenho.
Precisamos de algumas cores para fazer nossa arte:
verde=gtk.gdk.Color(0,48255,0,0)
preto=gtk.gdk.Color(0,0,0,0)
fundo=gtk.gdk.Color(65535,65535,65535,0)
Vamos dar um fundo branco para a nossa tela:
gc.set_rgb_fg_color(fundo)
tela.window.draw_rectangle(gc,True,0,0,800,600 )
Os dois comandos acima serão usados novamente agora, pois vamos percorrer a lista de quadrados e desenhar cada um deles. Se a lista estiver vazia, nenhum quadrado será desenhado:
for q in quadrados:
# desenhando um quadrado preenchido de verde
gc.set_rgb_fg_color(verde)
tela.window.draw_rectangle(gc,True,q[0],q[1],q[2],q[3])
#desenhando a borda preta do quadrado
gc.set_rgb_fg_color(preto)
tela.window.draw_rectangle(gc,False,q[0],q[1],q[2],q[3])
Em gc.set_rgb_fg_color( cor ) definimos a cor a ser usada ao desenhar.
O método draw_rectangle precisa ser compreendido. Vejamos os parâmetros usados:
gc : o graphics context criado lá em cima.
False ou True : indica se o quadrado será preenchido.
q[0] até q[3]: são os quatro valores do quadrado criado lá em cima.
Faltou o botão para apagar a tela. Ele está presente no código completo mais abaixo. Por enquanto basta dizer que apaga-se a tela simplesmente limpando a lista de quadrados e disparando novamente a função ‘desenha()’.
Vamos ver como ficou o nosso programa:
#!/usr/bin/env python
import pygtk
import gtk
#declarando a lista de quadrados
quadrados=[]
def cria_quadrado(tela,evento):
global quadrados
#obtendo as coordenadas do clique de mouse
coor=evento.get_coords()
x=coor[0]
y=coor[1]
#criando um novo quadrado e incluindo ele na lista
novo_quadrado=[x-25,y-25,50,50]
quadrados.append(novo_quadrado)
# disparando a funcao 'desenha()'
# para incluir o nosso novo quadrado
desenha(tela,None)
# a funcao desenha() deve ser chamada sempre que
# quisermos redesenhar a tela
# ou quando a tela precisar ser redesenhada
# por ter sido encoberta por outra janele, por
# exemplo
def desenha(tela,evento ):
global quadrados
#criando um "graphics context"
gc=tela.get_style().fg_gc[gtk.STATE_NORMAL]
#definindo as cores
verde=gtk.gdk.Color(0,48255,0,0)
preto=gtk.gdk.Color(0,0,0,0)
fundo=gtk.gdk.Color(65535,65535,65535,0)
#pintando o fundo da nossa tela
gc.set_rgb_fg_color(fundo)
tela.window.draw_rectangle(gc,True,0,0,800,600 )
# desenhando cada um dos quadrados
for q in quadrados:
#desenhando o quadrado preenchido
gc.set_rgb_fg_color(verde)
tela.window.draw_rectangle(gc,True,q[0],q[1],q[2],q[3])
#desenhando a borda do quadrado
gc.set_rgb_fg_color(preto)
tela.window.draw_rectangle(gc,False,q[0],q[1],q[2],q[3])
def limpar(botao):
global quadrados
global tela
#limpando a lista de quadrados
quadrados=[]
#disparando novamente a funcao "desenha()"
#para desenhar a tela branca sem nenhum quadrado
desenha(tela, None)
win=gtk.Window()
win.set_title( "medeubranco.wordpress.com - Desenhando na tela com PyGTK" )
win.set_size_request(800,600)
win.connect('destroy',gtk.main_quit)
box=gtk.VBox()
#aqui a nossa tela sendo criada
tela=gtk.DrawingArea()
tela.connect('expose-event',desenha)
tela.add_events( gtk.gdk.BUTTON_PRESS_MASK )
tela.connect('button-press-event',cria_quadrado)
botao=gtk.Button( "limpar" )
botao.connect("clicked",limpar)
win.add(box)
box.set_border_width(10)
box.pack_start(tela)
box.pack_start(botao,False)
win.show_all()
gtk.main()
Olha o resultado:

Na tentativa de manter este artigo o menos complexo possível, muita coisa foi omitida aqui. Há outros métodos de desenho além do draw_rectangle, e há outras formas de lidar com uma DrawingArea.
Para se aprofundar, você pode começar por aqui:
http://www.pygtk.org/pygtk2tutorial/sec-DrawingAreaWidgetAndDrawing.html
Espero que este tutorial tenha sido útil a você e que você encontre formas criativas de usar uma DrawingArea.
Até o próximo artigo deste blog.