
Este artigo mistura um pouco de tudo o que foi visto nos artigos anteriores:
Criando uma simples janela em PyGTK
Criando uma simples janela em PyGTK - parte II
DrawingArea - Desenhando na tela com PyGTK
Orientação a Objetos com python
Orientação a Objetos - Herança
Como aqui vamos usar o Glade, recomendo também uma visita ao blog do OgMaciel:
Vídeo Aula: Programando com Python e Glade
Vídeo Aula: Trabalhando com o Glade
Não deixe de ver também Mantendo A Sanidade Com O Glade.
Neste artigo vamos criar um programa em que você pode desenhar um polígono desenhando com o mouse.
Para isso, vamos estender a classe gtk.DrawingArea através da herança. Nossa classe estendida vai ser um DrawingArea com recursos que nós vamos adicionar.
Paralelamente, vamos fazer uma janela com o glade, um código que vai exibir a janela inserindo nela a nossa classe filha de DrawingArea.
A nossa classe tela herdando de DrawingArea:
import gtk
# do modulo gtk, importamos DrawingArea e vamos chamar de 'DA'
from gtk import DrawingArea as DA
class tela(DA):
def __init__(self):
# executanto o construtor da classe pai (DrawingArea)
DA.__init__(self)
Agora temos uma classe que faz tudo o que um DrawingArea faz. Podemos acrescentar recursos a ela.
Enquanto isso, vamos fazer a GUI no glade:
- crie uma janela;
- adicione uma “Caixa Vertical” (Vbox) com três itens;
- adicione um Rótulo (Label) na primeira seção da Caixa Vertical;
- em Empacotamento, mude para “não” as opções Expandir e Preencher;
- adicione um botão e em Geral mude o nome para ‘botão1′ (é, poderia ter ficado Button1 mesmo);
- em Empacotamento, mude para “não” as opções Expandir e Preencher;
- no espaço do meio, adicione uma ‘Porta de Visualização’ (ViewPort) ;
- mude o nome da ViewPort para ‘caixatela’
- explore as outras opções de configuração dos widgets
Sua janela deve ficar quase assim:

Voltemos à nossa classe.
O nosso widget será usado da seguinte forma:
Você pressiona o botão esquerdo do mouse sobre o widget e mantém pressionado. Arrasta então o ponteiro do mouse pela tela; uma linha será desenhada por onde passar o ponteiro. Ao soltar o botão do mouse, a linha se fechará em um polígono.
Ao Rolar a ‘rodinha’ do mouse, os últimos pontos do polígono serão removidos; continue rolando a rodinha que o polígono desaparecerá.
Temos então três eventos envolvidos na criação do desenho: botão pressionado, movimento do mouse e botão solto (‘button-press-event’, ‘button-release-event’ e ‘motion-notify-event’ ). Um quarto evento, o de rolagem da rodinha (’scroll-event’ ), está envolvido na operação de remover pontos do polígono.
class tela(DA):
def __init__(self):
DA.__init__(self)
self.definecores()
# atributo que determina se o botão está pressionado
self.apertou=False
# conectando o expose-event a uma função
# que vai pedir que a tela seja redesenhada
self.connect('expose-event',self.expose)
# adicionando os eventos de mouse
self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON_RELEASE_MASK |
gtk.gdk.MOTION_NOTIFY |
gtk.gdk.POINTER_MOTION_MASK
)
# conectando cada evento à sua função correspondente
# botão de mouse pressionado
self.connect('button-press-event',self.clica)
# soltando o botão
self.connect('button-release-event',self.solta)
# movimento de mouse
self.connect('motion-notify-event',self.arrasta)
# rolando a 'rodinha'
self.connect('scroll-event',self.rolou)
# criando uma lista vazia
# que vai conter os pontos da linha a ser desenhada
# ou o polígono
# cada ponto será uma tupla
# com as coordenadas (x,y)
self.linha=[]
Olhe o código acima, nas linhas 23, 25, 27 e 29. Quatro funções terão que ser definidas. Vejamos o que cada uma deve fazer:
- self.clica
- mudar a variável self.apertou para True
- adicionar o primeiro ponto (as coordenadas do clique) à lista self.linha
- self.arrasta
- se self.apertou é True, adiciona mais um ponto À lista e desenha o último segmento.
- self.solta
- mudar a variável self.apertou para False
- self.rolou
- remover o último ponto da lista e mandar a tela ser redesenhada
def solta(self, tela, evento):
self.apertou=False
self.desenha()
def clica(self, tela, evento):
if evento.button==3:
self.linha.pop()
return
self.linha.append((evento.x,evento.y))
self.apertou=True
def rolou(self,tela,evento):
try:
self.linha.pop()
self.desenha()
except:
pass
def arrasta(self,tela,evento):
if self.apertou:
self.linha.append((evento.x,evento.y))
Movendo o mouse com o botão pressionado
Após soltar o botão
O código completo da classe:
import gtk
from gtk import DrawingArea as DA
class tela(DA):
def __init__(self):
DA.__init__(self)
self.definecores()
self.apertou=False
self.connect('expose-event',self.expose)
self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON_RELEASE_MASK |
gtk.gdk.MOTION_NOTIFY |
gtk.gdk.POINTER_MOTION_MASK
)
self.connect('button-press-event',self.clica)
self.connect('button-release-event',self.solta)
self.connect('motion-notify-event',self.arrasta)
self.connect('scroll-event',self.rolou)
self.linha=[]
def definecores(self):
self.verde=gtk.gdk.Color(0,48255,0,0)
self.preto=gtk.gdk.Color(0,0,0,0)
self.branco=gtk.gdk.Color(65535,65535,65535,0)
self.vermelho=gtk.gdk.Color(65535,0,0,0)
self.amarelinho=gtk.gdk.Color(35535,65333,15000,0)
self.outra=gtk.gdk.Color(0,65535,65535,0)
self.azul=gtk.gdk.Color(0,0,65535,0)
def desenhaultimo(self):
if len(self.linha)>1:
x1=int(self.linha[-2][0])
y1=int(self.linha[-2][1])
x2=int(self.linha[-1][0])
y2=int(self.linha[-1][1])
self.gc.set_rgb_fg_color(self.vermelho)
self.window.draw_line(self.gc,x1,y1,x2,y2)
self.gc.set_rgb_fg_color(self.preto)
self.window.draw_rectangle(self.gc,False,x1-1,y1-1,2,2,)
self.window.draw_rectangle(self.gc,False,x2-1,y2-1,2,2,)
def solta(self, tela, evento):
self.apertou=False
self.desenha()
def clica(self, tela, evento):
if evento.button==3:
self.linha.pop()
return
self.linha.append((evento.x,evento.y))
self.apertou=True
def rolou(self,tela,evento):
try:
self.linha.pop()
self.desenha()
except:
pass
def arrasta(self,tela,evento):
if self.apertou:
self.linha.append((evento.x,evento.y))
self.desenhaultimo()
def apaga(self):
for pt in self.linha:
print pt
self.linha=[]
self.desenha()
def desenha(self):
a,b,c,d = self.get_allocation()
self.gc.set_rgb_fg_color(self.branco)
self.window.draw_rectangle(self.gc,True,0,0,c-1,d-1)
if len(self.linha)>0:
self.gc.set_rgb_fg_color(self.amarelinho)
self.window.draw_polygon(self.gc,True, self.linha)
self.gc.set_rgb_fg_color(self.preto)
self.window.draw_polygon(self.gc,False, self.linha)
self.gc.set_rgb_fg_color(self.preto)
self.window.draw_rectangle(self.gc, False,2,2,c-4,d-4 )
for pt in self.linha:
self.window.draw_rectangle(self.gc, False,pt[0]-1, pt[1]-1,2,2)
def expose(self,tela, evento):
self.gc=self.get_style().fg_gc[gtk.STATE_NORMAL]
self.gc.set_rgb_fg_color(self.branco)
self.desenha()
Para entender as operações de desenho, veja o artigo anterior: DrawingArea - Desenhando na tela com PyGTK
Salve este código como desenha.py
Salve seu projeto no Glade como parapintar.glade
E execute o código abaixo, que vai reunir tudo:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Código parcialmente reaproveitado
do código exemplo do OgMaciel
em http://blog.ogmaciel.com/?p=413
"""
import desenha
try:
import pygtk
pygtk.require( "2.0" )
except:
pass
try:
import gtk
import gtk.glade
except:
sys.exit(1)
class Janelao(object):
"""
Janela criada com o Glade
"""
def __init__(self):
self.xml = gtk.glade.XML( "parapintar.glade" )
self.xml.signal_autoconnect(self)
self.mainWindow = self.xml.get_widget( 'window1' )
self.mainWindow.set_title( "Pintor" )
# puxando a ViewPort criado no glade
self.caixa=self.xml.get_widget( 'caixatela' )
self.mainWindow.connect('destroy', gtk.main_quit)
self.botao = self.xml.get_widget( 'botao1' )
# criando uma instancia do nosso objeto
self.tela=desenha.tela()
#inserindo nosso objeto na viewport
self.caixa.add(self.tela)
self.botao.connect("clicked",self.apagar_tela)
self.tela.show()
self.mainWindow.show_all()
def apagar_tela(self,botao):
self.tela.apaga()
if __name__ == "__main__":
w = Janelao()
gtk.main()
