Há algumas semanas iniciei estudos sobre como usar Python, GTK e Cairo para desenvolver aplicativos de pintura digital. Li sobre a arquitetura e o fluxo de programas como Krita, GIMP, MyPaint e Clip Studio Paint, especialmente sua interface, o modelo dos pincéis e o pipeline de renderização. Embora GTK + Cairo seja minha escolha principal, também é possível criar soluções similares com Qt (usando PySide em Python ou C++ nativo).
Para montar essa base, utilizei dois recursos fundamentais:
-
Gtk.DrawingArea – fornece a “tela” onde tudo é desenhado e captura eventos de mouse/mesa digitalizadora.
-
Cairo – cria e gerencia os buffers de desenho, permitindo implementar o pincel e as operações gráficas.
No Windows, instalei o MSYS2 para obter o GCC, Python, GTK, Cairo e PyGObject; depois empacotei o executável com PyInstaller. No Linux, basta usar o gerenciador de pacotes (por exemplo, apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0
) para ter tudo pronto.
Introdução ao GTK + Cairo
-
GTK (GIMP Toolkit) é a biblioteca de GUI: janelas, botões, menus e áreas de desenho (
Gtk.DrawingArea
). -
Cairo é a biblioteca de gráficos 2D vetoriais: linhas, formas, texto e imagens, com antialiasing e transparência, via
cairo.Context
. -
Integração: sempre que a
DrawingArea
precisa ser redesenhada, o GTK emite o sinal"draw"
e passa um contexto Cairo (cr
) para sua função de callback. Você desenha nocr
, e o GTK exibe o resultado.
Fluxo resumido
-
Crie um widget
Gtk.DrawingArea
. -
Conecte o sinal
"draw"
ao seu método de desenho. -
No callback, use o
cairo.Context
para pintar formas, cores e texturas. -
Chame
queue_draw()
sempre que precisar atualizar a tela (por clique ou movimento).
Exemplo minimalista em Python
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
import cairo
class AreaDesenho(Gtk.DrawingArea):
def __init__(self):
super().__init__()
self.set_size_request(400, 300)
self.pontos = []
self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.POINTER_MOTION_MASK)
self.connect("draw", self.on_draw)
self.connect("button-press-event", self.on_press)
self.connect("motion-notify-event", self.on_move)
def on_draw(self, widget, cr):
# Limpa o fundo
cr.set_source_rgb(1, 1, 1)
cr.paint()
# Desenha traços
cr.set_source_rgb(0, 0, 0)
cr.set_line_width(2)
for p1, p2 in zip(self.pontos, self.pontos[1:]):
cr.move_to(*p1)
cr.line_to(*p2)
cr.stroke()
return False
def on_press(self, widget, event):
self.pontos.append((event.x, event.y))
self.queue_draw()
def on_move(self, widget, event):
if event.state & Gdk.ModifierType.BUTTON1_MASK:
self.pontos.append((event.x, event.y))
self.queue_draw()
class JanelaDesenho(Gtk.Window):
def __init__(self):
super().__init__(title="Desenho Digital")
self.set_default_size(400, 300)
self.connect("destroy", Gtk.main_quit)
self.add(AreaDesenho())
JanelaDesenho().show_all()
Gtk.main()
Como funciona
-
AreaDesenho
herda deGtk.DrawingArea
e armazena pontos do mouse. -
No evento
"draw"
, pinta o fundo e traça linhas entre os pontos coletados. -
Eventos de clique e arrasto (
button-press-event
emotion-notify-event
) registram os pontos e solicitam redesenho comqueue_draw()
.
Referências
-
Guia PyGObject (GTK+ 3): https://python-gtk-3-tutorial.readthedocs.io
-
Documentação PyCairo: https://pycairo.readthedocs.io
-
API GTK DrawingArea: https://docs.gtk.org/gtk3/class.DrawingArea.html
-
Tutorial Cairo Graphics: https://www.cairographics.org/tutorial/
-
ZetCode Cairo Python: https://zetcode.com/gfx/cairo/
Nenhum comentário:
Postar um comentário