Este documento apresenta um curso sobre Python-GTK. Ele descreve o objetivo, público-alvo, pré-requisitos, programação, avaliação e bibliografia do curso. Além disso, apresenta o conteúdo de 8 lições sobre desenvolvimento de interfaces gráficas com Python e GTK.
8. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
É dada permissão para copiar, distribuir e/ou modificar este documento sob os termos
da Licença de Documentação Livre GNU, Versão 1.1 ou qualquer versão posterior
públicada pela Free Software Foundation; com o Capitulo Invariante SOBRE ESSA
APOSTILA. Uma cópia da licença está inclusa na seção entitulada "Licença de Docu-
mentação Livre GNU".
Os 10 mandamentos do aluno de educação online
• 1. Acesso à Internet: ter endereço eletrônico, um provedor e um equipamento adequado é
pré-requisito para a participação nos cursos a distância.
• 2. Habilidade e disposição para operar programas: ter conhecimentos básicos de Informá-
tica é necessário para poder executar as tarefas.
• 3. Vontade para aprender colaborativamente: interagir, ser participativo no ensino a distân-
cia conta muitos pontos, pois irá colaborar para o processo ensino-aprendizagem pessoal,
dos colegas e dos professores.
• 4. Comportamentos compatíveis com a etiqueta: mostrar-se interessado em conhecer seus
colegas de turma respeitando-os e fazendo ser respeitado pelo mesmo.
• 5. Organização pessoal: planejar e organizar tudo é fundamental para facilitar a sua revisão
e a sua recuperação de materiais.
• 6. Vontade para realizar as atividades no tempo correto: anotar todas as suas obrigações e
realizá-las em tempo real.
• 7. Curiosidade e abertura para inovações: aceitar novas idéias e inovar sempre.
• 8. Flexibilidade e adaptação: requisitos necessário à mudança tecnológica, aprendizagens
e descobertas.
• 9. Objetividade em sua comunicação: comunicar-se de forma clara, breve e transparente é
ponto - chave na comunicação pela Internet.
• 10. Responsabilidade: ser responsável por seu próprio aprendizado. O ambiente virtual não
controla a sua dedicação, mas reflete os resultados do seu esforço e da sua colaboração.
Como participar dos fóruns e Wikipédia
Você tem um problema e precisa de ajuda?
Podemos te ajudar de 2 formas:
A primeira é o uso dos fóruns de notícias e de dúvidas gerais que se distinguem pelo uso:
. O fórum de notícias tem por objetivo disponibilizar um meio de acesso rápido a informações
que sejam pertinentes ao curso (avisos, notícias). As mensagens postadas nele são enviadas a
7
9. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
todos participantes. Assim, se o monitor ou algum outro participante tiver uma informação que
interesse ao grupo, favor postá-la aqui.
Porém, se o que você deseja é resolver alguma dúvida ou discutir algum tópico específico do
curso. É recomendado que você faça uso do Forum de dúvidas gerais que lhe dá recursos mais
efetivos para esta prática.
. O fórum de dúvidas gerais tem por objetivo disponibilizar um meio fácil, rápido e interativo
para solucionar suas dúvidas e trocar experiências. As mensagens postadas nele são enviadas
a todos participantes do curso. Assim, fica muito mais fácil obter respostas, já que todos podem
ajudar.
Se você receber uma mensagem com algum tópico que saiba responder, não se preocupe com a
formalização ou a gramática. Responda! E não se esqueça de que antes de abrir um novo tópico
é recomendável ver se a sua pergunta já foi feita por outro participante.
A segunda forma se dá pelas Wikis:
. Uma wiki é uma página web que pode ser editada colaborativamente, ou seja, qualquer par-
ticipante pode inserir, editar, apagar textos. As versões antigas vão sendo arquivadas e podem
ser recuperadas a qualquer momento que um dos participantes o desejar. Assim, ela oferece um
ótimo suporte a processos de aprendizagem colaborativa. A maior wiki na web é o site "Wikipé-
dia", uma experiência grandiosa de construção de uma enciclopédia de forma colaborativa, por
pessoas de todas as partes do mundo. Acesse-a em português pelos links:
• Página principal da Wiki - http://pt.wikipedia.org/wiki/
Agradecemos antecipadamente a sua colaboração com a aprendizagem do grupo!
Primeiros Passos
Para uma melhor aprendizagem é recomendável que você siga os seguintes passos:
• Ler o Plano de Ensino e entender a que seu curso se dispõe a ensinar;
• Ler a Ambientação do Moodle para aprender a navegar neste ambiente e se utilizar das
ferramentas básicas do mesmo;
• Entrar nas lições seguindo a seqüência descrita no Plano de Ensino;
• Qualquer dúvida, reporte ao Fórum de Dúvidas Gerais.
Perfil do Tutor
Segue-se uma descrição do tutor ideal, baseada no feedback de alunos e de tutores.
O tutor ideal é um modelo de excelência: é consistente, justo e profissional nos respectivos
valores e atitudes, incentiva mas é honesto, imparcial, amável, positivo, respeitador, aceita as
idéias dos estudantes, é paciente, pessoal, tolerante, apreciativo, compreensivo e pronto a ajudar.
8
10. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
A classificação por um tutor desta natureza proporciona o melhor feedback possível, é crucial, e,
para a maior parte dos alunos, constitui o ponto central do processo de aprendizagem.’ Este tutor
ou instrutor:
• fornece explicações claras acerca do que ele espera, e do estilo de classificação que irá
utilizar;
• gosta que lhe façam perguntas adicionais;
• identifica as nossas falhas, mas corrige-as amavelmente’, diz um estudante, ’e explica por-
que motivo a classificação foi ou não foi atribuída’;
• tece comentários completos e construtivos, mas de forma agradável (em contraste com um
reparo de um estudante: ’os comentários deixam-nos com uma sensação de crítica, de
ameaça e de nervossismo’)
• dá uma ajuda complementar para encorajar um estudante em dificuldade;
• esclarece pontos que não foram entendidos, ou corretamente aprendidos anteriormente;
• ajuda o estudante a alcançar os seus objetivos;
• é flexível quando necessário;
• mostra um interesse genuíno em motivar os alunos (mesmo os principiantes e, por isso,
talvez numa fase menos interessante para o tutor);
• escreve todas as correções de forma legível e com um nível de pormenorização adequado;
• acima de tudo, devolve os trabalhos rapidamente;
9
12. Capítulo 1
O que é o Curso
Python é uma linguagem interpretada, orientada a objetos, extensível e de fácil utilização.
GTK+ (Gimp Tool Kit) é uma biblioteca para criar interfaces gráficas.
Para utilizá-las em conjunto, foi criado o PyGTK, que consiste em uma série de módulos para
prover uma interface ao Python para acesso ao GTK, possibilitando ao desenvolvedor a criação
de sistemas com interfaces gráficas riquíssimas.
11
13. Capítulo 2
Plano de ensino
2.1 Objetivo
Habilitar técnicos e programadores a usarem a biblioteca PyGTK, para Python.
2.2 Público Alvo
Técnicos e Programadores que desejem trabalhar com PyGTK.
2.3 Pré-requisitos
Os usuários deverão ser, necessariamente, indicados por empresas públicas e ter certo co-
nhecimento da linguagem Python. É recomendável um conhecimento mínimo nos recursos es-
pecíficos da linguagem (por exemplo dicionários e tuplas). Noções de orientação a objetos em
Python também são recomendáveis.
Não é necessário conhecimento prévio de GTK+.
2.4 Descrição
O curso de Introdução ao Python será realizado na modalidade EAD e utilizará a plataforma
Moodle como ferramenta de aprendizagem. Ele é composto de um módulo de aprendizado que
será dado na primeira semana e um módulo de avaliação que será dado na segunda semana. O
material didático estará disponível on-line de acordo com as datas pré-estabelecidas no calendá-
rio. A versão utilizada para o PyGTK será a 2.10.
2.5 Metodologia
O curso está dividido da seguinte maneira:
12
14. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
2.6 Cronograma
• 1ª Semana - Introdução + Conceitos básicos;
• 2ª Semana - Conceitos avançados.
Todo o material está no formato de livro, e estará disponível ao longo do curso. O livro poderá
ser acessado quantas vezes forem necessárias. Aconselhamos a leitura de "Ambientação do
Moodle", para que você conheça o produto de Ensino a Distância, evitando dificuldades advindas
do "desconhecimento"sobre o mesmo.
Ao final de cada semana do curso será disponibilizada a prova referente ao módulo estudado
anteriormente que também conterá perguntas sobre os textos indicados. Utilize o material de
cada semana e os exemplos disponibilizados para se preparar para prova.
Os instrutores estarão à sua disposição ao longo de todo curso. Qualquer dúvida deve ser
disponibilizada no fórum ou enviada por e-mail. Diariamente os monitores darão respostas e es-
clarecimentos.
2.7 Programa
O curso oferecerá o seguinte conteúdo:
Semana 1:
• Visão Geral e Histórico;
• Introdução;
• Um breve exemplo;
• Modificando parâmetros;
• Callbacks;
• Widgets básicos.
Semana 2:
1. Outras widgets;
2. Aperfeiçoando o controle de layout;
3. Automatizando o processo de criação de interfaces.
2.8 Avaliação
Toda a avaliação será feita on-line.
Aspectos a serem considerados na avaliação:
• Iniciativa e autonomia no processo de aprendizagem e de produção de conhecimento;
• Capacidade de pesquisa e abordagem criativa na solução dos problemas apresentados.
13
15. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Instrumentos de avaliação:
• Participação ativa nas atividades programadas;
• Avaliação ao final do curso;
• O participante fará várias avaliações referente ao conteúdo do curso. Para a aprovação e
obtenção do certificado o participante deverá obter nota final maior ou igual a 6.0 de acordo
com a fórmula abaixo:
• Nota Final = ((ML x 7) + (AF x 3)) / 10 = Média aritmética das lições;
• AF = Avaliações.
2.9 Bibliografia
• Site official: http://www.python.org
• Guia: http://www.pygtk.org/pygtk2tutorial/index.html
14
16. Capítulo 3
Lição 1 - Apresentando PyGTK
3.1 Um breve histórico
Embora o curso assuma um certo conhecimento de Python, não é necessário que o aluno
tenha experiência com GTK+. Entretanto, isto não nos impede de oferecer uma visão geral de
todos os componentes envolvidos.
GTK+
O GIMP Toolkit, popularmente conhecido por GTK+, é um dos mais famosos toolkits voltados
para a criação de interfaces gráficas (referidas GUIs daqui em diante). O que, então, justifica a
parte GIMP do nome? Originalmente, foi idealizado para servir de base para o editor de imagens
GIMP (GNU Image Manipulation Program), mas acabou expandindo muito além.
O GTK+ é um dos pilares do famoso ambiente de janelas GNOME, portanto aplicações base-
adas nesta biblioteca podem ser facilmente identificadas pelo visual em comum.
Seus autores incluem Spencer Kimball, Peter Mattis e Josh MacDonald, todos os quais traba-
lhavam na Universidade de Berkeley à época de criação do GTK+/GIMP.
15
17. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Os menus, botões, formulários, dropdowns e outros elementos da janela (widgets) possuem
um visual bastante padronizado, mesmo entre os vários temas disponíveis no GTK+ (acima re-
presentado está o tema padrão da distribuição Ubuntu).
Python
Python é uma linguagem de programação de alto nível orientada a objetos. Seu criador, Guido
van Rossum, a criou em 1991 com o objetivo de enfatizar o esforço do programador sobre o es-
forço computacional, tornando-se uma linguagem de fácil aprendizagem.
Além do mais, Python se difere de outras linguagens no quesito simplicidade e legibilidade.
Por exemplo, a indentação do código é de prima importância para que o código execute correta-
mente, o que conseqüentemente facilita bastante a sua compreensão e padroniza os programas
com um look similar. O caractere ; não é necessário para indicar o término de um comando,
servindo a quebra de linha (n) para tal.
Quanto ao aspecto de simplicidade, isto apenas se aplica ao núcleo da linguagem. Há uma
vasta quantidade de bibliotecas disponíveis, inclusive distribuídas com o Python. Uma destas,
aliás, é o...
16
18. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
PyGTK
Como o leitor mais atento deve ter percebido, o objetivo deste curso é aliar o Python e o GTK+
através da biblioteca PyGTK. Dispensando explicações sobre a origem de seu nome, partiremos
para um overview geral.
O PyGTK é um conjunto de wrappers (vulgarmente "envoltórios") para a biblioteca GTK+. As-
sim como o Python, o PyGTK é software livre, no entanto é distribuído sob a licença LGPL. É de
autoria de um dos desenvolvedores do GNOME, James Henstridge, e hoje possui uma equipe
maior, inclusive com grande participação da comunidade através de patches e bug reports.
Um dos méritos do PyGTK é ter sido escolhido como o ambiente de escolha para aplicações
rodando nos sistemas do projeto One Laptop Per Child. Além disso, algums outros projetos usam
o PyGTK, tais como:
• Instalador Anaconda (usado no Fedora);
• Bittorrent (cliente);
• GNOME Sudoku (ótimo passatempo).
3.2 Primeiros passos
Talvez a melhor forma de se passar a conhecer uma ferramenta previamente desconhecida
seja instalando-a, e em seguida rodando um simples exemplo para testá-la e familiarizar-se com
o que está por vir.
É exatamente o que será feito.
Instação
O Linux é, decididamente, a plataforma ideal para este tipo de desenvolvimento e é a que nós
recomendamos. Não obstante, usuários de Windows podem seguir com o curso, assim como
os de Mac OS X. Apenas a etapa de instalação deverá diferir do que está apresentado no curso
(Devido à indisponibilidade de recursos, a tarefa de instalçao será deixada por conta do usuário).
Linux
Talvez até excessivamente simples, para se instalar o PyGTK nas distribuições Debian e de-
rivados (tais como Ubuntu), basta instalar o pacote python-gtk2:
apt-get install python-gtk2
Isto irá instalar as bibliotecas necessárias. Caso seja solicitado para instalar pacotes depen-
dentes, aceite.
Caso esteja usando outra distribuição, procure um pacote com este nome ou pygtk.
17
19. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
3.3 Conferindo a instalação
OK, tecnicamente estamos prontos para seguir em frente e aprendermos os conceitos. Mas
primeiro vamos verificar se a etapa de instalação realmente foi concluída com êxito.
Crie um arquivo com o seguinte código usando seu editor predileto:
import pygtk
import gtk
# Teste inicial
class Janela:
def __init__ (self):
self.janela = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.janela.show()
def main (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main()
Salve-o como "testando123.py"e execute-o (python testando123.py).
Enfrentou algum problema? Envie sua dúvida ao fórum! Não será possível prosseguir com o
curso se este exemplo não funcionar.
Não se preocupe com o código, iremos detalhá-lo mais adiante.
Perceba que este exemplo apenas exibe uma janela vazia. Nem mesmo o botão de fechá-la
funciona. Veremos os motivos mais adiante.
18
20. Capítulo 4
Lição 2 - Apresentando Widgets,
Signals e Callbacks
4.1 Conceitos básicos
Antes de prosseguirmos com os exemplos, iremos dar uma breve olhada nos conceitos que
serão explorados. Estes são de crucial importância para o entendimento pleno da matéria. Usuá-
rios que não possuem experiência prévia com GTK+: leiam esta página atenciosamente.
Widgets
Um conceito extremamente simples; derivado de window gadets (apetrechos de janela), o
termo pode representar qualquer elemento de uma janela, tais como botões, barras de rolagem,
menus dropdown, campo de texto, barra de título, barra de ferramentas e qualquer outra parafer-
nália que possa estar contida em uma janela. Em suma, tudo representado é um widget.
Sinais
O GTK+ é um chamado event-driven toolkit, significando que uma vez que se atinge o gtk.main(),
o processo adormece até que um evento ocorra e o controle seja redirecionado para a função
correspondente. Este conceito é denominado sinal (entretanto este conceito é meramente seme-
lhante aos signals Unix, a implementação é bastante diferente). Quando ocorre um evento, como
o apertar de um botão, o widget irá emitir um sinal. Os sinais variam de widget para widget. Por
exemplo, o botão herda sinais de várias classes:
• gobject.GObject: "activate", "clicked", "enter", "leave", "pressed"e "released";
• gtk.Object: "destroy";
• gtk.Widget: "accel-closures-changed", "button-press-event", "button-release-event", "can-
activate-accel", "child-notify", dentre muitas, muitas outras;
19
21. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
• gtk.Container: "add", "check-resize", "remove", "set-focus-child".
Para o exemplo do botão, a lista completa de sinais pode ser encontrada em:
http://www.pygtk.org/docs/pygtk/class-gtkbutton.html#signal-prototypes-gtkbutton.
Percebe-se que a quantidade possível de sinais é imensa para um dado widget, e neste curso
iremos ver apenas os signals mais freqüentemente utilizados.
Callback
Quando um sinal ocorre, uma função callback pode ser acionada. Esta função pode alterar
a interface, abrir uma janela popup, fechar o programa, conectar a um banco de dados, enfim: é
o elo entre os widgets e o resto do programa. Como, então, associar uma função callback a um
signal? Para tal, os objetos em GTK possuem a função connect:
handler_id = object.connect (name, func, func_data)
Nesta linha, object é a instância do GtkWidget que estará emitindo o sinal, e o primeiro argu-
mento (name) indica o nome do sinal que irá acionar o callback (por exemplo "clicked"ou "des-
troy"). O segundo argumento (func) indica a função (callback) que deverá ser acionada. Repare
que o argumento é o *objeto* da função, e não o seu nome. No terceiro argumento, estão os
dados que serão repassados para a função.
Portanto o callback deverá ter o seguinte cabeçalho:
def callback_func (widget, callback_data)
O primeiro parâmetro será um ponteiro para a widget que emitiu o sinal, e o segundo parâme-
tro um ponteiro para os dados definidos na chamada do connect.
Naturalmente, se a função callback for definida em um método, sua forma geral será:
def callback_func_method (self, widget, callback_data)
Onde self representa a instância do object acionando o método.
(Existem exceções quanto aos seus argumentos, mas de forma geral serão estes.)
Juntos, estes dois conceitos (signals e callbacks) formam boa parte dos fundamentos por trás
do GTK+.
Eventos
Além dos sinais, existem também eventos, que refletem o mecanismo de eventos do X. São
muito similares a sinais, no sentido que callbacks também podem ser associados a estes. Re-
fletem eventos tais como o requisitado fechamento de um programa, ou o clique do mouse (ou
duplo-, triplo-clique). No entanto, o cabeçalho de suas funções callback é um pouco diferente:
def callback_func (widget, event, callback_data)
ou, no caso de uma função callback definida em um método:
def callback_func_method (self, widget, event, callback_data)
20
22. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Como fazer para conectar uma função callback a um evento? Usando connect:
handler_id = object.connect (name, func)
Por exemplo, para um botão pode-se definir o evento da seguinte forma:
handler_id = botao.connect ("button_press_event", button_click_event)
No momento do evento, isto iria invocar a seguinte função:
button_click_event (widget, event, callback_data)
O valor que esta função retorna indica se o evento deverá ser propagado pelo mecanismo
de gerenciamento de eventos do GTK+. Se retornar True, significa que o evento já foi tratado e
não deverá propagar (isto é, se houver mais de um callback associado a um evento). Se retornar
False, então o evento será propagado.
Se isto ainda está um pouco nebuloso, não se preocupe. Exemplos tornarão os conceitos
bem mais claros.
Desconectando callbacks
É claro, também é possível desassociar um callback de um sinal ou um evento. O comando a
ser usado é o seguinte:
object.disconnect (handler_id)
4.2 Um exemplo prático
Agora que temos um embasamento teórico podemos partir para exemplos.
Crie um arquivo com o nome botao1.py com o seguinte conteúdo:
#!/usr/bin/env python
# -*- coding: latin-1 -*-
import pygtk
import gtk
class Janela:
def __init__ (self):
""" Primeiro criamos uma janela do tipo WINDOW_TOPLEVEL.
Isto é feito através da geração de uma instância da classe
Window. """
self.janela = gtk.Window (gtk.WINDOW_TOPLEVEL)
""" Ajustamos alguns parâmetros referentes à janela:
- Ajusta o espaçamento da borda para 10 (espaço entre
borda e os widgets)
- Seta o título da janela
21
23. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
- Altera o tamanho da janela
"""
self.janela.set_border_width (10)
self.janela.set_title ("Pythonizando GTK+")
self.janela.resize (300, 100)
""" Associa o callback self.delete_event ao evento
delete_event. Caso isso não fosse feito, o programa
continuaria sua execução mesmo após o fechamento da
janela """
self.janela.connect ("delete_event", self.delete_event)
""" Em seguida cria-se um botão (perceba que é a isntância de
uma classe. """
self.botao = gtk.Button ("Hey there")
""" IMPORTANTÍSSIMO: (quase) todo elemento deve ser
explicitamente exibido para que apareça na tela. """
self.botao.show ()
""" Adiciona o botão à janela. Para adicionar mais elementos
será necessário criar um container, como veremos adiante """
self.janela.add (self.botao)
""" Exibe a janela (e consequentemente tudo contido nela). """
self.janela.show ()
def delete_event (self, widget, event):
gtk.main_quit()
return False
def main (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main()
O resultado será algo assim:
A maior parte do código é bastante intuitiva; a criação da janela, atribuição de parãmetros, cria-
ção do botão. Há dois elementos importantes neste exemplo: o callback e as chamadas a show().
22
24. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
O método show() causa uma widget a ser exibida assim que possível. Antes de se chamar
este método a widget não será mostrada! Naturalmente, para que uma widget seja visualizada, é
necessário também que todos os contêineres da widget também sejam explicitamente mostrados.
Quando um contêiner "toplevel"(que contém outros widgets) é mostrado, este é imediatamente
mapeado e exibido na tela, assim como todos os widgets contidos dentro deste que já estejam
exibidos. É por este motivo que a ordem de chamada deve começar das widgets internas até
chegar nas widgets externas; caso contrário o usuário irá ver a atualização dos componentes
dependendo da complexidade gráfica do GUI.
Outro aspecto importante do exemplo é o callback usado para o fechamento do programa.
O evento "delete_event"é chamado quando o sistema operacional recebe uma solicitação de fe-
chamento do programa. Isto pode ocorrer quando o usuário clica no X para fechar, ou pelo
gerenciador de tarefas. Em todo caso, se não tratarmos este evento a widget em questão (no
caso a janela em si) será finalizada, no entanto o gtk.main() continuará sua execução (Tente isto:
remova o self.janela.connect e veja o que ocorre depois de fechada a janela). Por esse motivo é
necessário explicitamente executar gtk.main_quit(). O dado passado pelo delete_event (no quarto
parâmetro da função callback) é None e portanto é ignorado pela função callback.
Você consegue ver a utilidade disto? Nem sempre que o usuário fecha uma janela ele neces-
sariamente teve tal intenção. O browser Firefox confirma o fechamento da janela se mais de uma
aba estiver aberta. O OpenOffice pergunta se deseja salvar o documento antes de fechar. É este
evento o responsável por essas ações.
23
25. Capítulo 5
Lição 3 - Widgets elementares
5.1 Empacotando widgets
Até o momento trabalhamos com apenas uma widget na janela principal. Como fazer para
agrupá-las?
Há várias formas de fazê-lo; a mais comum delas são caixas (boxes).
Boxes
Boxes são contêineres transparentes nos quais podem ser empacotados outras widgets.
Pode-se usar tanto o HBox (horizontal) quanto o VBox (vertical). Ao empacotar elementos no
HBox eles podem ser inseridos da esquerda para a direita ou da direita para a esquerda, depen-
dendo da forma como sejam criados. É comum usar uma combinação de boxes (boxes dentro de
boxes) para criar o efeito desejado.
Como é de se esperar, para criar um HBox basta gerar uma instância de gtk.HBox(). Para
adicionar elementos a um box, usa-se o método pack_start() e pack_end(), onde o primeiro in-
sere da esquerda para a direita e o último da direita para a esquerda. Boxes podem agrupar tanto
widgets quanto outros boxes.
Vale frisar que botões são contêineres por si só, mas normalmente usa-se apenas um label
dentro do botão.
Como criá-los?
O cabeçalho da HBox() está definido da seguinte forma:
gtk.HBox (homogeneous = False, spacing = 0)
Se o primeiro parâmetro for True, isto garantirá que todos os elementos tenham exatamente a
mesma largura. O segundo parâmetro especifica o espaçamento entre os elementos.
Além disso, a forma como se agrupa os elementos também altera a aparência geral do layout:
box.pack_start(child, expand=True, fill=True, padding=0)
24
26. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Box é o container onde o widget será empacotado e o parâmetro child deve ser o objeto do widget
a ser empacotado. Os outros parâmetros controlam como os widgets inseridos se adaptarão ao
box (ou vice-versa):
• Expand define se o objeto se ajustará para ocupar todo o espaço disponível no widget (True)
ou se o box se reduzirá ao tamanho dos widgets (False). Se isto for False, é possível manter
todos os widgets alinhados no canto direito ou esquerdo do box;
• O parâmetro fill somente tem efeito se o expand for false; neste caso, ele controla se o es-
paço remanescente no box deverá ser alocado como espaçamento entre os widgets (False)
ou se os widgets receberão o espaço remanescente (True).
• Finalmente padding é o espaçamento que será adicionado a ambos os lados do widget.
Qual a diferença entre padding (fornecido no pack_start() ou pack_end()) e spacing (fornecido
no HBox() ou VBox())? O spacing é o espaço adicionado entre os elementos, e o padding é o
espaço adicionado a ambos os lados de um elemento.
Toda essa teoria também se aplica ao VBox, invertendo-se os eixos.
Exemplificando
Observe o exemplo a seguir, botao2.py:
#!/usr/bin/env python
# -*- coding: latin-1 -*-
import pygtk
import gtk
class Janela:
def __init__ (self):
# Primeiro criamos uma janela do tipo WINDOW_TOPLEVEL.
self.janela = gtk.Window (gtk.WINDOW_TOPLEVEL)
# Ajustamos alguns parâmetros referentes à janela:
self.janela.set_border_width (10)
self.janela.set_title (u"Botões 2")
self.janela.resize (300, 50)
# Em seguida cria-se os botões:
self.botao1 = gtk.Button ("Hey there")
self.botao2 = gtk.Button ("Au revoir", gtk.STOCK_QUIT)
# Associa o callback self.delete_event ao evento
# delete_event.
self.janela.connect ("delete_event", self.delete_event)
# Especificamos o argumento data como None
self.botao1.connect ("clicked", self.button_click, None)
25
27. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
self.botao2.connect ("clicked", self.delete_event, None)
# Exibe-os
self.botao1.show ()
self.botao2.show ()
# Cria-se um HBox homogêneo (todos elementos ocupam o mesmo
# espaço) com espaçamento 10 entre os elementos.
self.hbox = gtk.HBox (True, 10)
# Empacota os botões no HBox
self.hbox.pack_start (self.botao1)
self.hbox.pack_start (self.botao2)
# Adiciona o botão à janela. Para adicionar mais elementos
# será necessário criar um contêiner, como veremos adiante
self.janela.add (self.hbox)
# Exibe o hbox
self.hbox.show ()
# Exibe a janela
self.janela.show ()
def delete_event (self, widget, event):
gtk.main_quit()
def button_click (self, widget, event):
print "Hullo"
def main (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main()
O resultado deve ser o seguinte:
Obviamente pode-se ir muito além disso, encapsulando vários boxes e criando um layout extre-
mamente flexível.
26
28. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
5.2 O widget do botão
Vimos no exemplo anterior que botões podem ser customizados com parâmetros adicionais.
Já sabemos praticamente tudo sobre botões, mas há alguns truques dos quais devemos estar
cientes.
A sintaxe básica para criar um botão é:
button = gtk.Button(label=None, stock=None)
O primeiro parâmetro especifica o texto a ser exibido (opcional) e o stock pode ser uma de várias
constantes pré-definidas com padrões de botões (também opcional). O stock (STOCK_QUIT)
usado no exemplo da lição anterior é um botão tipicamente usado para sair de programas. A
variedade completa está disponível em http://www.pygtk.org/docs/pygtk/gtk-stock-items.html.
Dica: Sendo a usabilidade um aspecto muito importante nos aplicativos de atualmente, é co-
mum que programas suportem atalhos de teclado em vez de necessitar que se use o mouse. Por
isto, para sublinhar uma letra do label, basta prefixá-la com ’_’. Isto se aplica a todos os botões
vistos nesta página. Assim, ao apertar Alt+(letra sublinhada), seria como se o usuário clicasse no
botão.
Customizando o visual
Há de se convir que as possibilidades são bastantes limitadas se não se pode ao menos criar
um botão com um ícone customizado; tem de haver uma forma de se criar um botão diferenciado;
e de fato existe. Analise o seguinte exemplo, botao3.py:
#!/usr/bin/env python
# -*- coding: latin-1 -*-
import pygtk
import gtk
class Janela:
def __init__ (self):
# Primeiro criamos uma janela do tipo WINDOW_TOPLEVEL.
self.janela = gtk.Window (gtk.WINDOW_TOPLEVEL)
# Ajustamos alguns parâmetros referentes à janela:
self.janela.set_border_width (10)
self.janela.set_title (u"Botões 3")
self.janela.resize (100, 50)
# Assegura-se que a janela será fechada corretamente.
# (Lembre-se de funções lambda em Python!)
self.janela.connect("destroy", lambda wid: gtk.main_quit())
self.janela.connect("delete_event", lambda a1,a2:gtk.main_quit())
27
29. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
# Em seguida cria-se o botão (perceba a ausência do label)
self.botao = gtk.Button ()
# Cria-se o box do botão...
self.box = self.xpm_label_box ("tartan.xpm", u"faça algo!")
# E adiciona o HBox com os conteúdos do botão
self.botao.add (self.box)
# Exibe-os
self.box.show()
self.botao.show ()
# Adiciona o botão á janela. Para adicionar mais elementos
# será necessário criar um container, como veremos adiante
self.janela.add (self.botao)
# Exibe o hbox
self.box.show ()
# Exibe a janela
self.janela.show ()
def xpm_label_box (self, xpm_arquivo, label_texto):
# Cria-se o HBox não-homogêneo (o ícone é menor que o label)
# e sem espaçamento.
box = gtk.HBox (False, 0)
# Adiciona uma pequena borda como em um botão
box.set_border_width (2)
# NOVIDADE: cria a imagem
imagem = gtk.Image()
imagem.set_from_file (xpm_arquivo)
# Cria o label
label = gtk.Label (label_texto)
# Adiciona a imagem e o label ao box
box.pack_start (imagem, False, False, 3)
box.pack_start (label, False, False, 3)
# Mostra tudo
imagem.show()
label.show()
return box
28
30. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
def main (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main()
Preste atenção ao exemplo e perceberá que não é possível criar um botão com um pixmap
diferenciado "nativamente", na realidade criamos um HBox no qual estão contidos o pixmap e
o label. O método que usamos, xpm_label_box, poderia com facilidade ser usado em qualquer
outro elemento que possa ser um contêiner.
A propósito, para se criar o pixmap podemos usar uma diversidade de programas, inclusive o
open-source GIMP.
Outros botões
Outras formas de botões são freqüentemente vistas, como toggle buttons (que possuem um
relevo para indicar se estão selecionados ou não), checkboxes (uma pequena caixa que pode
ser marcada ou desmarcada) e radio buttons (conjunto de botões dos quais apenas um pode ser
selecionado através de pequenas bolas). Na ausência de uma tradução melhor irei me referir aos
nomes originais, em inglês.
Toggle buttons
Toggle buttons são derivados de botões normais e são muito similares, exceto o fato de que
sempre estarão em um de dois estados (pressionado ou não), alterados através de um clique.
Seu estado se altera a cada clique. Estes botões são a base para check buttons e radio buttons,
com muitas similaridades na implementação.
Como criar um?
botao = gtk.ToggleButton(label=None)
Cada widget deste tipo possui uma função get_active() que retorna se o botão está pressionado
ou não; o sinal que indica que o estado de um botão foi alterado é o "toggled"; juntando as
duas peças do quebra-cabeça, rapidamente descobrimos como trabalhar com as mudanças de
estados:
def toggle_button_callback (widget, data):
if (widget.get_active()):
# botão está pressionado
else:
# botão não está pressionado
29
31. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
A função get_active() pode ser usada sempre que se precisar obter o estado do botão, sendo
que esta retornará True (pressionado) ou False (não-pressionado).
E como alterar o estado do botão manualmente? Usa-se o seguinte método:
botao.set_active(active)
Onde active pode ser True (pressionado) ou False (não-pressionado). O valor inicial (quando o
botão é gerado) é False.
Perceba que quando esta função for chamada, os sinais "clicked"e "toggled"serão emitidos
pelo botão!
Check buttons
Como já foi mencionado, seu funcionamento é muito parecido com toggle buttons, e de fato,
são simplesmente toggle buttons com uma aparência diferente, já que os labels ficam na lateral
da "caixinha"que o usuário marca. A criação é feita da seguinte forma:
botao = gtk.CheckButton(label=None)
O callback de verificação de estado (get_active()) pode ser feito da mesma forma que nos toggle
buttons, assim como o ajuste de estado (set_active()).
Radio buttons
Radio buttons são similares aos check buttons, mas possuem a diferenciação de serem agru-
pados de tal forma que apenas um pode estar selecionado por vez. Isto é bom quando a lista de
opções é razoavelmente pequena.
A criação é feita com o seguinte comando:
botao = gtk.RadioButton (group=None, label=None)
Perceba a existência de um argumento extra. Radio buttons requerem de um grupo para funcio-
nar. A primeira chamada para gtk.RadioButton() deverá passar como argumento de group None,
e um novo grupo de radio buttons será criado com o novo botão.
Para adicionar mais radio buttons para o grupo, passe a referência para um radio button nas
chamadas subseqüentes a gtk.RadioButton().
É também uma boa idéia explicitar qual botão deverá estar apertado inicialmente com o co-
mando
button.set_active(is_active)
Isto funciona da mesma forma como foi descrito acima. Uma vez que radio buttons estão agrupa-
dos, apenas um do grupo pode estar ativo. Por este motivo, se o usuário clicar em um, depois em
30
32. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
outro botão de dado grupo, o primeiro radio button irá emitir o sinal "toggled"(já que foi desativado)
e o segundo botão também irá emitir o sinal "toggled"(já que acabara de ser pressionado).
Recapitulando
No intuito de fixar e exemplificar o que foi visto acima, preste atenção no exemplo botao4.py.
#!/usr/bin/env python
# -*- coding: latin-1 -*-
import pygtk
import gtk
class Janela:
# Função callback que monitora o estado dos botões
def callback (self, widget, data=None):
print "Botao %s foi %s." % (data, ("desselecionado",
s "selecionado")[widget.get_active()])
def __init__ (self):
# Primeiro criamos uma janela do tipo WINDOW_TOPLEVEL.
self.janela = gtk.Window (gtk.WINDOW_TOPLEVEL)
# Ajustamos alguns parâmetros referentes à janela:
self.janela.set_border_width (10)
self.janela.set_title (u"Botões + botões")
self.janela.resize (200, 400)
# Assegura-se que a janela será fechada corretamente.
# (Lembre-se de funções lambda em Python!)
self.janela.connect("destroy", lambda wid: gtk.main_quit())
self.janela.connect("delete_event", lambda a1,a2:gtk.main_quit())
vbox = gtk.VBox (True, 2)
toggle1 = gtk.ToggleButton("Toggle button 1")
toggle1.connect ("toggled", self.callback, "Toggle button 1")
toggle2 = gtk.ToggleButton("Toggle button 2")
toggle2.connect ("toggled", self.callback, "Toggle button 2")
vbox.pack_start (toggle1, False, False, 2)
toggle1.show()
vbox.pack_start (toggle2, False, False, 2)
toggle2.show()
checkbox1 = gtk.CheckButton("Checkbox 1")
checkbox1.connect ("toggled", self.callback, "Checkbox 1")
checkbox2 = gtk.CheckButton("Checkbox 2")
checkbox2.connect ("toggled", self.callback, "Checkbox 2")
31
33. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
vbox.pack_start (checkbox1, False, False, 2)
checkbox1.show()
vbox.pack_start (checkbox2, False, False, 2)
checkbox2.show()
radio1 = gtk.RadioButton(None, "Radio button 1")
radio1.connect ("toggled", self.callback, "Radio button 1")
radio2 = gtk.RadioButton(radio1, "Radio button 2")
radio2.connect ("toggled", self.callback, "Radio button 2")
radio3 = gtk.RadioButton(radio2, "Radio button 3")
radio3.connect ("toggled", self.callback, "Radio button 3")
vbox.pack_start (radio1, False, False, 2)
radio1.show()
vbox.pack_start (radio2, False, False, 2)
radio2.show()
vbox.pack_start (radio3, False, False, 2)
radio3.show()
# E adiciona o HBox com os conteúdos do botão
self.janela.add (vbox)
# Exibe-os
vbox.show()
# Exibe a janela
self.janela.show ()
def main (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main()
Screenshot do programa em ação:
32
34. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Mensagens são emitidas no terminal a cada alteração nos botões.
Repare como a criação do radio button é diferente dos demais, assim como o seu funciona-
mento.
33
35. Capítulo 6
Lição 4 - Widgets miscelâneas 1
6.1 Adjustments
Um elemento muito frequente em interfaces com usuários é o "slider", uma barra de rolagem
através da qual o usuário pode escolher uma faixa de valores. Eis um exemplo:
O GTK+ obviamente suporta tais widgets, mas primeiro devemos entender um pouco sobre a
teoria por trás de seu funcionamento.
Adjustments
Uma aplicação necessita reagir às ações de usuários nestes widgets; isto poderia ser feito
através de um sinal emitido pela widget quando houvesse uma mudança no seu valor, no qual
a widget transmite também o novo valor para a função responsável. Mas e se quiséssemos as-
sociar os ajustes de várias widgets, de tal forma, que mudar o valor em uma widget alteraria
outra? Uma aplicação prática para isto seria conectar as barras de rolagem de tal forma a sele-
cionar o conteúdo a ser visualizado, por exemplo, de uma imagem(Será isso um presságio?). Se
cada widget de ajuste tivesse de emitir um sinal a cada mudança de valor, o programador teria
de escrever gerenciadores de sinais para transmitir a mudança de valor de uma widget para outra.
O GTK+ nos auxilia através do objeto Adjustment, que não é uma widget, mas uma forma
através da qual widgets podem transmitir informações sobre ajustes de uma forma abstrata e
flexível. Além de guardarem parâmetros de configuração e valores de widgets (ou várias delas),
Adjustments podem emitir sinais, assim como widgets convencionais, e isso pode ser usado para
propagar informações entre várias widgets separadas.
Você já conhece bem esse tipo de widget; são barras de progresso, janelas com barra de
rolagem, dentre outros.
Criando um Adjustment
A sintaxe é simples:
34
36. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
adjustment = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0, page_size=0)
O parâmetro value indica o valor inicial a ser atribuído à widget. Lower e upper são o menor e
maior valores que podem ser assumidos pelo widget. Step_incr define o intervalo entre os ajus-
tes, page_incr define o maior intervalo entre estes. Finalmente o page_size é o parâmetro que
contém a área visível no caso de uma widget à qual se aplique.
Os widgets ajustáveis podem ser divididos naqueles que necessitam de uma unidade espe-
cífica (por exemplo pixels) e aqueles que usam números arbitrários. Alguns widgets que usam
números arbitrários incluem a barra de rolagem e a barra de progresso. Estas podem ser ajus-
tadas pelo mouse ou pelo teclado, e a faixa de valores pode ser definida no ajuste. Por padrão,
manipular tal widget apenas altera o valor de seu Adjustment.
O outro grupo inclui o widget de texto e a janela com barra de rolagem. Estes necessitam va-
lores em pixels para seus Adjustments. Alguns widgets que podem ser ajustados indiretamente
usando barras de rolagem, a exemplo do ScrolledWindow que veremos adiante.
Adjustments podem também ser manipulados manualmente. Para alterar o valor de um objeto
Adjustment, usamos
adjustment.set_value(value)
Como já dissemos, Adjustments são capazes de emitir sinais (por serem derivados da classe
Object, assim como outros widgets) e por este motivo mudanças se propagam automaticamente
quando por exemplo uma barra de rolagem conectada a outra widget é alterada; todas widgets
ajustáveis se conectam através do sinal value_changed.
6.2 Widgets de faixa de valores
Com um pouco de bagagem sobre Adjustments, podemos voltar ao tópico inicial da lição.
Como se pode imaginar, todas as widgets de faixa de valores são associadas a um objeto
Adjustment, através da qual estas calculam as dimensões da barra de rolagem.
Barra de rolagem
São os widgets mais simples desta categoria e é uma das quais mais lidamos. São apropria-
das para mudar aspectos de outras widgets, como uma lista, uma caixa de texto ou um viewport.
Para outras funcionalidades (como escolher um valor específico) é mais recomendável usar wid-
gets de escala, que são mais amigáveis e possuem mais funcionalidades.
Podemos criá-las através do seguinte comando (horizontal ou vertical):
hscroll = gtk.HSrollbar (adjustment=None)
vscroll = gtk.VSrollbar (adjustment=None)
35
37. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
O parâmetro pode ser um adjustment criado pela função mostrada na seção anterior. Na
omissão deste será criado um adjustment automaticamente, que pode subseqüentemente ser
obtido através de funções auxiliares.
Widget de escala
Idêntico ao exemplo dado no início da lição, widgets Scale permitem que o usuário manipule
um valor em uma faixa específica. Pode ser usado, por exemplo, para alterar o zoom de uma
página ou o contraste de uma imagem.
Estes widgets possuem 2 tipos: 1 para widgets horizontais outro para widgets verticais (a
versão horizontal é mais comum). Funcionam exatamente da mesma maneira. Para criá-los:
vertical_scale = gtk.VScale (adjustment=None)
horizontal_scale = gtk.HScale (adjustment=None)
Vê o parâmetro adjustment? É através deste que se pode "linkar"widgets a um adjustment em
comum. Caso seja omitido, o adjustment será criado pela função com todos os valores ajustados
em 0.0, o que não é muito útil. Como o page_size pode afetar o valor máximo da widget (além do
especificado pelo parâmetro upper), é recomendado que se ajuste o page_size em 0.0 para que
o valor upper coincida com o maior valor que o usuário possa selecionar.
Opções
Algumas widgets de escala exibem o valor escolhido ao seu lado; isto pode ser feito através
da seguinte função:
scale.set_draw_value (draw_value)
Onde draw_value pode ser True ou False. O número de casas decimais exibido pode ser ajustado
através de:
scale.set_digits (digits) (o limite é 13)
Para definir a posição relativa onde o valor será representado, usa-se:
scale.set_value_pos (pos)
Onde o argumento pos pode ser qualquer um de POS_LEFT, POS_RIGHT, POS_TOP ou
POS_BOTTOM.
Política de atualização
Como você já sabe, o sinal "value_changed"é emitido quando o valor é alterado. Mas quando
exatamente é isso? A qualquer mudança? Apenas quando o usuário pára de mover a barra da
widget? Há 3 políticas de atualização:
36
38. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
• UPDATE_CONTINUOUS: Emite o sinal value_changed continuamente, mesmo que a barra
seja movida muito pouco;
• UPDATE_DISCONTINUOUS: Emite o sinal value_changed apenas quando o valor da wid-
get não está em movimento e o usuário solta o botão do mouse;
• UPDATE_DELAYED: Emite o sinal value_changed se o usuário soltar o botão do mouse, ou
se a barra ficar parada por um curto instante.
Para ajustar uma destas políticas faça o seguinte:
range.set_update_policy (policy)
Obtendo e usando um adjustment
Às vezes o adjustment não é criado explicitamente, sendo isto feito através da criação de uma
widget que o necessita. Nestes casos podemos obter o adjustmente através de:
adjustment = range.get_adjustment()
Da mesma forma, para configurar uma widget para usar outro adjustment usamos:
range.set_adjustment(adjustment)
(Perceba que o set_adjustment() não surtirá efeito se o adjustment for o mesmo em uso pela
widget, mesmo que seus valores tenham sido alterados. Para tal seria adequado emitir o sinal
"changed"através de adjustment.emit("changed").)
6.3 Labels
Labels (rótulos) estão entre os widgets mais simples, no entanto são um dos mais frequente-
mente usados. Simplesmente exibem texto que não é editável pelo usuário, como o usado em
um formulário para indicar os campos correspondentes. Para criá-los:
label = gtk.Label (str)
Onde str deve conter o valor inicial a ser assumido pelo label. Para alterar este texto posterior-
mente à sua criação:
label.set_text (str)
Da mesma forma pode-se obter o texto já contido em um label:
str = label.get_text ()
Além disso, estas widgets podem exibir texto ao longo de várias linhas quando a str os contém.
É possível também fazer com que a widget automaticamente acrescente as quebras de linha:
37
39. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
label.set_line_wrap (wrap)
Onde o parâmetro wrap pode ser True ou False.
Muitas outras opções são suportadas; como sempre recomenda-se referir à documentação
original:
http://www.pygtk.org/docs/pygtk/class-gtklabel.html.
6.4 Áreas com barras de rolagem
Ainda no tópico de adjustments e widgets com faixa de valores, um dos widgets mais úteis
que utilizam esse recurso é o ScrolledWindow. Consiste em uma área (um viewport) sendo que
apenas uma parte pode ser exibida. Barras de rolagem nas laterais permitem que o usuário
selecione a área a ser visualizada. (Podem ser omitidas caso a área possa ser exibida na sua
íntegra, tanto no eixo horizontal quanto no eixo vertical.) O melhor de tudo é o fato de tudo isto
ser uma única widget! Veja só:
scrolled_window = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
Os dois parâmetros são os adjustments a serem usados no sentido horizontal e vertical da wid-
get. Usualmente não é necessário especificá-los.
Para definir quando as barras de rolagem deverão ser exibidas, usa-se
scrolled_window.set_policy(hscrollbar_policy, vscrollbar_policy)
Onde cada um desses valores pode ser POLICY_AUTOMATIC (determina automaticamente se a
barra de rolagem deverá estar disponível) ou POLICY_ALWAYS (sempre estará disponível).
Para adicionar o widget que se deseja exibir ao ScrolledWindow:
scrolled_window.add_with_viewport(child)
6.5 Exemplo
Temos a seguir um simples exemplo (misc1.py) que usa os conceitos aprendidos nesta lição.
O exemplo não é particularmente útil, mas ilustra bem os conceitos aprendidos.
#!/usr/bin/env python# -*- coding: latin-1 -*-import pygtk
import gtk
38
40. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
classJanela:
def__init__ (self):
# Primeiro criamos uma janela do tipo WINDOW_TOPLEVEL.
self.janela = gtk.Window (gtk.WINDOW_TOPLEVEL)
# Ajustamos alguns parâmetros referentes à janela:
self.janela.set_border_width (10)
self.janela.set_title (u"Widgets miscelâneos")
self.janela.resize (200, 400)
# Assegura-se que a janela será fechada corretamente.
# (Lembre-se de funções lambda em Python!)
self.janela.connect("destroy", lambda wid: gtk.main_quit())
self.janela.connect("delete_event", lambda a1,a2:gtk.main_quit())
# Conteiner de todos os elementos
vbox = gtk.VBox (False, 2)
# Widgets de faixa de valores
hadjustment = gtk.Adjustment()
vadjustment = gtk.Adjustment()
# Cria os widgets de escala usando o recém-criado adjustment
hscale = gtk.HScale(hadjustment)
vscale = gtk.HScale(vadjustment)
39
41. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
hscale.show()
vscale.show()
# Widgets label
hlabel = gtk.Label("Ajuste horizontal:")
vlabel = gtk.Label("Ajuste vertical:")
hlabel.show()
vlabel.show()
# Imagem que sera encapsulada
image = gtk.Image()
image.set_from_file ("fall_wallpaper_10.jpg")
image.show()
# Contêiner da imagem
scrolled_window = gtk.ScrolledWindow(hadjustment, vadjustment)
scrolled_window.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scrolled_window.add_with_viewport(image)
scrolled_window.show()
# Acrescenta todos os elementos ao VBox
vbox.pack_start (hlabel, False, False, 2)
vbox.pack_start (hscale, False, False, 2)
vbox.pack_start (vlabel, False, False, 2)
40
42. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
vbox.pack_start (vscale, False, False, 2)
vbox.pack_start (scrolled_window, True, True, 2)
# E adiciona o HBox com os conteúdos do botão
self.janela.add (vbox)
# Exibe-os
vbox.show()
# Exibe a janela
self.janela.show ()
defmain (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main(
Screenshot:
41
43. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
42
44. Capítulo 7
Lição 5 - Widgets miscelâneas 2
7.1 Barras de progresso
Iremos nesta lição continuar a exploração pelas widgets do GTK+. Todas estas são vistas
com bastante freqüência.
Barras de progresso
Todo usuário as conhece; são usadas para representar o processo de uma operação. Como
tudo no GTK+, são fáceis de se criar e manipular:
progressbar = gtk.ProgressBar(adjustment=None)
O parâmetro adjustment (opcional) pode receber um adjustment criado previamente. Reveja a
lição anterior se necessário.
Para alterar o valor exibido pela barra de status, usa-se
progressbar.set_fraction(fraction)
Onde fraction é um número entre 0 e 1, representando a percentagem da barra que deverá estar
preenchida.
É também possível que o preenchimento ocorra da direita para esquerda (ou outros), em vez
de ser da esquerda para a direita:
progressgar.set_orientation(orientation)
orientation pode assumir um dos seguintes valores:
• PROGRESS_LEFT_TO_RIGHT: da esquerda para a direita;
• PROGRESS_RIGHT_TO_LEFT: da direita para a esquerda;
• PROGRESS_BOTTOM_TO_TOP: de baixo para cima;
43
45. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
• PROGRESS_TOP_TO_BOTTOM: de cima para baixo.
Além de poder exibir uma fração, a barra pode também indicar que um processo está ocor-
rendo sem precisar o quanto da operação foi concluído. Para isso, usa-se pulse:
progressbar.pulse()
Isto exibe uma barra oscilante. E para configurar o tamanho desta barra, usa-se:
progressbar.set_pulse_step (fraction)
Onde fraction novamente é um valor entre 0 e 1.
Para configurar e obter um texto a ser exibido na barra, temos os seguintes comandos: p
rogressbar.set_text (text)
text = progressbar.get_text ()
7.2 Dialogs
O widget Dialog é também conhecido como pop-up por alguns. Consiste em uma janela com
alguns elementos empacotados (um vbox (chamado vbox) para conteúdo e um hbox (chamado
action_area) para botões e ações que o usuário possa realizar). Sua criação é bastante simples:
dialog = gtk.Dialog(title=None, parent=None, flags=0, buttons=None)
Onde title é o título do Dialog, parent é a janela principal da aplicação e flags setam as várias
opções de criação, dentre elas:
• DIALOG_MODAL - Faz com que o usuário não possa manipular a janela principal, apenas
a que foi criada;
• DIALOG_DESTROY_WITH_PARENT - Força que o Dialog seja destruído quando sua janela
principal for fechada;
• DIALOG_NO_SEPARATOR - Omite o separador enter vbox e action_area.
Para adicionar elementos ao Dialog basta empacotar usando pack_start() ou pack_end() no
vbox ou action_area do Dialog. Por exemplo:
dialog.action_area.pack_start(button, True, True, 0)
dialog.vbox.pack_start(label, True, True, 0)
Podem ser manipulados como se fossem janelas (isto é, callbacks para "destroy"funcionarão
normalmente, por exemplo).
44
46. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
7.3 Barras de status
São widgets relativamente simples que exibem uma mensagem por vez. Servem para auxi-
liar o usuário na interação com um programa; por exemplo, quando sobrepor o mouse sobre um
ícone a barra de status pode comunicar a funcionalidade do botão. Ou então informar sobre o
progresso de um processo.
Para que permita que várias partes da aplicação utilizem a mesma barra de status, tem-se o
que se chama de identificadores de contexto, que identificam os diferentes "usuários". Ela tam-
bém tem uma pilha que assegura que a mensagem a ser exibida sempre será a que está no topo
da pilha. (Ou seja, seu funcionamento é LIFO, last in first out).
Para criar uma barra de status:
statusbar = gtk.Statusbar()
Para requisitar-se um identificador de contexto, usa-se a seguinte função, que recebe também
uma breve descrição do contexto:
context_id = statusbar.get_context_id (description)
Para inserir uma mensagem, deve-se especificar o id do contexto bem como o texto a ser exibido:
message_id = statusbar.push (context_id, message)
A remoção da última mensagem adicionada naquele contexto é feita assim:
statusbar.pop (context_id)
E a remoção de uma mensagem específica:
statusbar.remove (context_id, message_id)
Lembre-se que a mensagem a ser exibida sempre será a última que foi adicionada (através de
push). Como se pode perceber, cada parte do programa pode interagir com a barra de status de
forma independente, já que terá seu próprio context_id.
7.4 Exemplo
Como de praxe, terminaremos esta lição de widgets com um exemplo sobre o que foi apren-
dido.
45
47. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Por motivos didáticos foi usado um timeout, tópico que não será visto neste curso, para
a atualização automatizada da barra de progresso. No entanto basta saber que timer = gob-
ject.timeout_add(interval, function, ...) irá executar a cada intervalo milisegundos a função func-
tion. Para que se cancele a execução de um timeout, usa-se gobject.source_remove (timer).
Ao código, misc2.py:
#!/usr/bin/env python# -*- coding: latin-1 -*-import pygtk
import gtk
import gobject
defprogress_timeout (pbobj):
# Cria valor (valor atual + 1%)
valor = pbobj.progressbar.get_fraction() + 0.01
if valor > 1.0:
# Atingimos 100%, fechar popup
pbobj.dialog.destroy()
# Ao retornar "False" garantimos que progress_timeout cessará de ser
#chamadoreturn False
# Atualiza valor da barra de progresso
pbobj.progressbar.set_fraction(valor)
# Returna True para que o callback continue sendo executado.return True
classJanela:
defdestroy_popup (self, widget, context_id):
# Fechamento do popup
46
48. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
self.statusbar.pop(context_id)
gobject.source_remove (self.timer)
defbotao_popup (self, widget, dialog):
# Aborta operação do popup
dialog.destroy()
defpopup (self, data):
# Criação da janela pop-up (perceba a referência à janela que a criou)
self.dialog = gtk.Dialog ("Processando...", self.janela, gtk.DIALOG_MODAL)
# Adiciona-se um botão ao "action_area" (area inferior do pop-up)
button = gtk.Button ("Abortar!")
button.connect ("clicked", self.botao_popup, self.dialog)
button.show()
self.dialog.action_area.pack_start (button, True, True, 5)
# Adiciona-se uma barra de progresso ao "vbox" (area superior do pop-up)
self.progressbar = gtk.ProgressBar ()
self.progressbar.set_text ("Por favor aguarde...")
self.progressbar.show()
self.dialog.vbox.pack_start (self.progressbar, True, True, 5)
47
49. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
# Cria um timeout que atuailza periodicamente o status da barra de progresso
self.timer = gobject.timeout_add (100, progress_timeout, self)
# Atualiza a mensagem da barra de status na janela principal para indicar atividade
context_id = self.statusbar.get_context_id ("popup")
message_id = self.statusbar.push (context_id, "Processando...")
# Associa o fechamento da janela a dsetroy_popup# (para remover a mensagem da barra
#de status)
self.dialog.connect ("destroy", self.destroy_popup, context_id)
# Exibe o pop-up
self.dialog.show()
def__init__ (self):
# Primeiro criamos uma janela do tipo WINDOW_TOPLEVEL.
self.janela = gtk.Window (gtk.WINDOW_TOPLEVEL)
# Ajustamos alguns parâmetros referentes à janela:
self.janela.set_border_width (10)
self.janela.set_title (u"Widgets miscelâneos")
self.janela.resize (200, 80)
48
50. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
# Assegura-se que a janela será fechada corretamente.# (Lembre-se de funções lambda
# em Python!)
self.janela.connect("destroy", lambda wid: gtk.main_quit())
self.janela.connect("delete_event", lambda a1,a2:gtk.main_quit())
# Contêiner de todos os elementos
vbox = gtk.VBox (False, 2)
# Cria o botão que iniciará a ação
button = gtk.Button (u"Faça algo!")
button.connect ("clicked", self.popup)
button.show()
# Cria a barra de status e adiciona uma mensagem inicial
self.statusbar = gtk.Statusbar()
context_id = self.statusbar.get_context_id ("main")
message_id = self.statusbar.push (context_id, "Em standby.")
self.statusbar.show()
# Insere os elementos recém-criados no vbox
vbox.pack_start (button, True, True, 2)
vbox.pack_end (self.statusbar, False, False, 0)
# E adiciona o HBox com os conteúdos do botão
49
51. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
self.janela.add (vbox)
# Exibe-os
vbox.show()
# Exibe a janela
self.janela.show ()
defmain (self):
gtk.main()
if __name__ == "__main__":
janela = Janela()
janela.main()
Screenshot do programa em execução:
50
52. Capítulo 8
Lição 6 - Widgets miscelâneas 3
8.1 Menus
Em GTK+ existem várias formas possíveis de se criar menus. Neste curso iremos ver a forma
mais manual, por motivos didáticos. Os outros métodos abstraem parte do funcionamento o que
acaba sendo prejudicial para o aprendizado.
São 3 os widgets usados para se fazer uma barra de menus e submenus:
• O item de menu, que o usuário clica para realizar a ação solicitada (por exemplo "Fechar");
• O menu, que atua como contêiner para os itens de menu, e;
• A barra de menus, que serve de contêiner para cada um dos menus.
Uma abstração do termo item de menu deve ser feita, já que seu widget pode ser usado
tanto para criar os itens de menu que efetivamente realizam a ação solicitada pelo usuário (por
exemplo "Novo", "Recortar", "Colar"), quanto para os elementos na barra de menus (por exemplo
"Arquivo", "Editar").
Começando pelo topo, criaremos a barra de menus:
menu_bar = gtk.MenuBar()
51
53. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Dispensando maiores explicações, esta função cria a barra de menus, que poderá subseqüen-
temente ser adicionada a outro contêiner.
menu = gtk.Menu()
Esta função retorna uma referência para um novo menu. Não é necessário chamar a função
show(), pois serve apenas de contêiner para os itens de menu.
menu_item = gtk.MenuItem(label=None)
Finalmente, o item de menu. Este recebe um rótulo (label), que será interpretado por carac-
teres mnemônicos precedidos de "_". É necessário que se chame a função show() pra que seja
exibido. Não confunda item de menu com menu! O primeiro é o botão associado a uma ação, e
o segundo é um contêiner para itens de menu.
A adição de um item de menu ao menu é feita através do comando append:
menu.append(menu_item)
E, finalmente, a associação de ações aos itens de menu é feita de forma convencional:
menu_item.connect_object ("activate", menuitem_response, "menu_action")
OK, temos o menu pronto. Precisa-se de uma barra de menus:
menu_bar = gtk.MenuBar()
widget.add (menu_bar)
menu_bar.show()
No entanto, lembre-se que o menu em si não pode ser exibido; a exibição do mesmo será
feita através de um item de menu, que será então adicionado à barra de menus:
menu_item_arquivo = gtk.MenuItem("Arquivo")
menu_item_arquivo.show()
menu_item_arquivo.set_submenu(menu)
Caso se queira que o item fique alinhado à direita, podemos usar o seguinte comando antes
de adicioná-lo à barra de menus:
menu_item.set_right_justified (right_justified)
52
54. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Finalmente, o adicionamos à barra de menus, finalizando a construção:
menu_bar.append (menu_item_arquivo)
Afinal, não foi tão difícil quanto possa parecer! Mas agora que você já entende os elementos
de construção do menu, caso deseje automatizar este procedimento, é possívei tanto escrever
funções auxiliares ou usar as formas embutidas no GTK+: ItemFactory ou UIManager. Desde
PyGTK 2.4, o uso do ItemFactory está depreciado, portanto deve-se usar o UIManager, que
constrói o menu a partir de uma estrutura XML.
8.2 Entrada de texto
Um elemento crucial de interfaces deixado de fora até o momento é o campo onde o usuário
pode entrar com conteúdo livre (texto). Em GTK+ um tal widget é o Entry. Este permite criar um
campo simples, de apenas uma linha.
A sintaxe de criação é a seguinte:
entry = gtk.Entry (max=0)
Onde max é o limite de caracteres permitido, e o valor 0 indica a ausência da limitação. Sua
alteração é possível após a criação:
entry.set_max_length (max)
Da mesma forma é possível alterar o conteúdo (texto):
entry.set_text (text)
(Como a classe Entry é derivada da classe Editable, aquela suporta algumas funções tais
como insert_text; a lista completa pode ser visualizada em http://www.pygtk.org/docs/pygtk/class-
gtkeditable.html).
entry.set_editable(editable)
entry.set_visibility(visible)
Estes comandos permitem, respectivamente, habilitar e desabilitar a edição de seu conteúdo
por parte do usuário (onde editable pode ser True ou False), e permitir ou não a visualização do
conteúdo sendo digitado. Isto pode ser útil em campos de senhas.
53
55. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
8.3 Spin buttons
Este tipo de botão pode ser usado pelo usuário para se escolher entre uma faixa de valores
numéricos. Seu funcionamento rege em torno dos Adjustments; reveja a lição caso seja neces-
sário.
A criação do spin button é feita assim:
spin_button = gtk.SpinButton(adjustment=None, climb_rate=0.0, digits=0)
O adjustment será automaticamente criado caso seja omitido, e é o que controla a faixa de
valores do widget. O climb rate indica a quantidade de aceleração que o botão tem ao ser pres-
sionado (variando entre 0.0 e 1.0), e digits é a quantidade de casas decimais que deve ser exibida.
É possível também alterar esses valores:
spin_button.configure (adjustment, climb_rate, digits)
que obedece à mesma sintaxe descrita acima.
Da mesma forma é possível alterar apenas outros parâmetros:
spin_button.set_adjustment (adjustment)
spin_button.set_digits (digits)
spin_button.set_value (value)
Ou obter o valor do spin button:
float_value = spin_button.get_value()
int_value = spin_button.get_value_as_int()
A alteração do valor também pode ser feita de forma relativa através da função spin:
spin_button.spin (direction, increment)
onde direction pode assumir um dos seguintes valores:
• SPIN_STEP_FORWARD - Aumenta o valor do spin button de acordo com o valor increment
ou page_increment (do Adjustment) caso increment seja igual a 0;
54
56. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
• SPIN_STEP_BACKWARD - Diminui o valor do spin button de acordo com o valor increment
ou page_increment (do Adjustment) caso increment seja igual a 0;
• SPIN_PAGE_FORWARD - Aumenta o valor do spin button de acordo com o valor increment;
• SPIN_PAGE_BACKWARD - Diminui o valor do spin button de acordo com o valor increment;
• SPIN_HOME - Ajusta o valor para o mínimo do Adjustment;
• SPIN_END - Ajusta o valor para o máximo do Adjustment;
• SPIN_USER_DEFINED - Altera o valor pela quantidade especificada.
Algumas funções podem controlar a aparência e o comportamento do botão de forma mais
detalhada:
spin_button.set_numeric (numeric)
Se numeric for True, isto garantirá que o usuário pode digitar apenas números no spin button;
caso contrário outros caracteres poderão ser digitados.
spin_button.set_wrap (wrap)
Já este comando faz com que, caso wrap seja True, o botão retorne ao valor mínimo quando o
usuário atingir o valor máximo e vice-versa.
spin_button.set_snap_to_ticks (snap_to_ticks)
Esta função faz com que valores "quebrados"sejam arredondados para seus equivalentes mais
próximos explicitados pelo Adjustment.
spin_button.set_update_policy (policy)
Onde policy pode ser UPDATE_ALWAYS ou UPDATE_IF_VALID, onde o primeiro atualiza o valor
mesmo que este seja inválido (após uma alteração), e o segundo ignora erros enquanto estiver
convertendo para valor numérico.
8.4 Diálogo de seleção de arquivo
Este é um dos widgets mais visto nos programas, por isso seria extremamente entediante
se cada desenvolvedor tivesse de programar tal funcionalidade, sem contar que provavelmente
seriam inconsistentes.
55
57. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Com isso em mente, os desenvolvedores do GTK+ incluiram isso como uma widget fácil de
se usar. Para criá-la:
filesel = gtk.FileSelection(title=None)
Para alterar o endereço sendo exibido, temos:
filesel.set_filename (filename)
O que irá atualizar a janela de maneira correspondente.
Para obter o arquivo selecionado:
filename = filesel.get_filename()
Como são várias as widgets que compõem o file selection dialog, é possível manipular essas
widgets "internas"normalmente. Elas seguem o seguinte padrão de nomes:
56
58. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
filesel.dir_list
filesel.file_list
filesel.selection_entry
filesel.selection_text
filesel.main_vbox
filesel.ok_button
filesel.cancel_button
filesel.help_button
filesel.history_pulldown
filesel.history_menu
filesel.fileop_dialog
filesel.fileop_entry
filesel.fileop_file
filesel.fileop_c_dir
filesel.fileop_del_file
filesel.fileop_ren_file
filesel.button_area
filesel.action_area
Em particular, é útil manipular os sinais do ok_button, cancel_button e help_button para atribuir
funcionalides aos mesmos.
Ficará como exercício ao leitor experimentar com os widgets apresentados nesta lição, já que
o funcionamento destes é praticamente idêntico aos apresentados anteriormente.
57
59. Capítulo 9
Lição 7 - Controle avançado de layout
9.1 Alignment
O widget de alinhamento (Alignment) permite que se adicione um widget em uma posição e
tamanho relativo ao widget de alinhamento. Por exemplo, pode ser usado para se centralizar um
botão na tela.
Existem apenas dois comandos a serem aprendidos:
alignment = gtk.Alignment (xalign=0.0, yalign=0.0, xscale=0.0, yscale=0.0)
align.set (xalign, yalign, xscale, yscale)
Como é de se esperar, o gtk.Alignment cria uma widget de alinhamento com os parâmetros
especificados. Os valores são em ponto-flutuante, e devem variar entre 0.0 e 1.0. O xalign e
yalign ajustam a posição do widget no Alignment. Estas propriedades especificam a fração de
espaço vazio que deve ser adicionado ao topo (yalign) ou à esquerda (xalign) do widget inserido.
Os outros dois parâmetros (xscale e yscale) definem a quantidade de espaço vazio que deve
ser absorvido pela widget: 0.0 não absorve nenhum espaço, e 1.0 absorve todo o espaço vazio
disponível. Naturalmente se ambos xscale e yscale forem iguais a 1.0, então o uso do widget de
alinhamento perde seu sentido, já que todo espaço vazio será absorvido.
Para adicionar um (e apenas um) widget ao alinhamento, usa-se alignment.add(widget).
Screenshot para transmitir a idéia:
58
60. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
9.2 Contêiner Fixed
O contêiner fixo permite que se posicione widgets em uma posição, ..., fixa. Esta posição é
relativa à ponta superior esquerda. Além disso, a posição dos widgets pode ser alterada dinami-
camente.
Novamente são poucos os comandos que precisam ser aprendidos:
fixed = gtk.Fixed()
fixed.put (widget, x, y)
fixed.move (widget, x, y)
O primeiro comando cria o widget (fixed) ao qual poderão ser adicionados outros (widget). O
segundo adiciona a widget desejada (widget) ao widget fixo (fixed) na posição x e y. O terceiro
meramente muda a widget de posição.
É possível adicionar vários widgets a um layout do tipo fixo.
Veja o seguinte exemplo:
59
61. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Estes devem ser usados com cautela, já que algumas configurações locais (como tamanho
de fontes) serão ignorados, como a posição é absoluta.
9.3 Contêiner layout
O contêiner Layout é bastante similar ao último visto (Fixed), com a exceção de que ele im-
plementa uma área infinita (ou melhor dizendo, até 2^32 pixels, devido a uma restrição do X).
Também se assemelha a um layout Fixed adicionado a uma ScrolledWindow, mas sem as barras
de rolagem. É basicamente a mesma idéia implementada de forma um pouco diferente.
A criação é feita usando
layout = gtk.Layout (hadjustment=None, vadjustment=None)
Como se pode perceber, é possível especificar objetos do tipo Adjustment que o widget Layout
irá usar para barra de rolagem. Omiti-los significa que novos adjustments serão criados.
Para respectivamente adicionar e mover widgets, usa-se
layout.put(widget, x, y)
layout.put(widget, x, y)
O tamanho do contêiner Layout pode ser ajustado e obtido usando estes 2 comandos:
60
62. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
layout.set_size (width, height)
size = layout.get_size()
Finalmente, para obter e manipular os Adjustments
hadj = layout.get_hadjustment()
vadj = layout.get_vadjustment()
layout.set_hadjustment(adjustment)
layout.set_vadjustment(adjustment)
Perceba que este contêiner não inclui a barra de rolagem, sendo necessário adicioná-las manu-
almente.
Veja o seguinte exemplo:
9.4 Frames
Frames normalmente são usados para agrupar widgets de forma clara e objetiva. Ao contrário
dos últimos widgets de agrupamento, este agrupa de forma visível ao usuário. Pode ser usado,
por exemplo, para separar seções em um grande formulário, ou para separar opções de partes
distintas de um programa.
Criá-los é simples:
frame = gtk.Frame (label=None)
O label é a descrição (visível) do agrupamento, que por padrão estará no canto superior esquerdo.
Pode também ser omitido. É possível também alterá-lo, através do comando
frame.set_label(label)
61
63. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Para mudar a posição do label, usa-se a função
frame.set_label_align (xalign, yalign)
Onde o parâmetro xalign pode variar entre 0.0 (esquerda) e 1.0 (direita). Atualmente o yalign não
é usado.
A adição de uma widget ao frame é feita usando-se frame.add (widget).
Exemplo:
9.5 Paned Window
Muitas vezes, por exemplo em um programa de e-mail, se deseja dividir uma área em 2 partes
tal que o usuário possa controlar o tamanho de cada uma dessas áreas. O GTK+ permite que se
faça isso diretamente através de 2 funções:
hpane = gtk.HPaned()
vpane = gtk.VPaned()
A HPane() criará uma divisória horizontal (ou seja, uma área superior e outra inferior), o VPane()
fará o seu equivalente vertical.
Para adicionar um elemento a cada uma das áreas, temos os seguintes comandos:
paned.add1(child)
paned.add2(child)
O add1 adicionará o widget desejado ao painel superior (ou esquerdo), enquanto o add2 o
adicionará ao painel inferior (ou direito).
62
64. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
63
65. Capítulo 10
Lição 8 - Progredindo com PyGTK
10.1 Progredindo com PyGTK
O que foi visto neste curso serve apenas de base para que o programador possa se aventurar
nas aplicações mais avançadas do Python/GTK+. Com algumas centenas de funções, boa parte
do conteúdo não foi visto porque o curso se tornaria repetitivo, mas a base para seu entendimento
pleno está presente no curso.
Algumas fontes recomendadas para o contínuo aprendizado:
http://www.pygtk.org/
http://www.pygtk.org/tutorial.html
http://www.pygtk.org/reference.html
Com isto encerra-se a matéria do curso propriamente dito.
Vale frisar que o curso foi bastante teórico, e permite ao programador entender todos os con-
ceitos e conhecer boa parte dos widgets e seu funcionamento. No entanto existem métodos mais
fáceis de se realizar a tarefa de diagramação de interfaces usando-se ferramentas tais como
Glade. Por não ser matéria do curso em si, veremos isso apenas de forma superficial.
10.2 Matéria extra: Criando interfaces gráficas usando PyGTK e
Glade
O primeiro passo é a instalação. No Debian e derivados, os pacotes necessários são python-
glade2 (contém as bibliotecas para o Python) e glade-2 (contém o construtor de interfaces). Por-
tanto como usuário root execute o seguinte comando:
apt-get install python-glade2 glade-2
Em seguida execute o glade-2, para se deparar com o seguinte:
64
66. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Inicialmente o Glade abre com um projeto novo e vazio. Repare que o projeto não contém
janelas ainda. Clique no ícone da janela na paleta (o primeiro ícone) que isto automaticamente
cria uma janela vazia. Em seguida, é possível alterar as propriedades do elemento recém-criado,
no caso a janela. Em "Propriedades"altere Name para JanelaPrincipal e Title para o que quiser.
Para adicionar elementos na janela, eles são "empacotados". Tendo a noção de como funci-
ona no nível do código fonte (ou seja, tendo feito o curso) o programador já tem todo o conheci-
mento que precisa para criar interfaces com facilidade.
Vamos criar uma interface muito simples, com apenas 2 widgets: um label e um botão. Por-
tanto siga os seguintes passos:
65
67. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
1. Clique no botão VBox (Vertical Box) na palheta;
2. Em seguida clique na janela para criar o VBox. Irá parecer uma janela solicitando o número
de células; reduza o valor para 2;
3. Clique no botão Label na palheta;
4. Clique na primeira célula do VBox recém-criado para adicioná-lo lá.
Viu? Temos um VBox com um elemento empacotado. Podemos alterar o conteúdo deste
rótulo para algo mais apropriado. Como a janela Properties sempre exibe as propriedades da
widget selecionada, mude o campo Label para "Clique abaixo!"Da mesma forma é possível alterar
muitas outras características que foram vistas ao longo do curso. Lembre-se de experimentar os
ajustes disponíveis também nas outras abas, tais como Packing.
Falta agora somente o botão; clique no seu respectivo botão na palheta e clique na segunda
célula do VBox para adicioná-lo. Em seguida altere o seu nome (Name) para botao1 e o rótulo
(Label) para "Clique em mim."
Ao término deste processo devemos ter algo assim:
66
68. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Clique em Project –> Save para salvar o projeto em uma pasta própria. O resultado disso
serão 2 arquivos XML que descrevem a interface. Abra-os em um editor de texto para ter uma
noção de como a interface é descrita.
Ou seja, o Glade não gera código em si, e sim uma descrição. O python-glade2 foi instalado
por esse motivo: permitir com que o código faça uso de arquivos .glade.
OK, para ver a interface em funcionamento, crie um arquivo com o seguinte conteúdo:
import sys
import pygtk
67
69. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
import gtk
import gtk.glade
class GladeTest:
def __init__ (self):
self.wTree = gtk.glade.XML("project2.glade")
self.window = self.wTree.get_widget("window1")
gtk.main()
if __name__ == "__main__":
glade_test = GladeTest()
Execute-o e verifique seu funcionamento.
Perceba que a biblioteca gtk.glade está sendo usada; esta foi instalada no início da lição. A
primeira chamada dentro do __init__ carrega a interface contida no arquivo XML (vide documen-
tação aqui):
Este objeto respresenta uma ’instanciação’ da interface descrita em XML. Quando um desses
objetos é criado, o arquivo XML é lido, e a interface é criada. O objeto gtk.glade.XML provê uma
interface para acessar as widgets através dos nomes associados a estas na descrição XML.
A segunda carrega o widget especificado que, no caso, é uma janela. Finalmente gtk.main()
inicia a execução.
Mas e se quiséssemos usar sinais e eventos assim como fizemos até o momento? Vamos lá...
O primeiro passo é conectar o evento "destroy"da janela à função gtk.main_quit() como fize-
mos em todos os programas até o momento. Volte ao Glade e selecione a janela principal no
projeto. Vá para a janela de propriedades e escolha a aba Signals. Em "Signal"escolha "des-
troy"(disponível em GtkObject).
68
70. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
E clique em "Add"para adicioná-lo:
Com isso criamos um handler que funciona de forma semelhante a um sinal.
Faremos o mesmo para o botão; clique no botão "Clique em mim", e na janela Propriedades
(aba Signals) escolha o sinal "clicked". Em seguida clique em add.
69
71. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
Logo temos 2 handlers a gerenciar: on_window1_destroy e on_botao1_clicked. Esses nomes
podem ser alterados, mas é recomendável que sigam um padrão.
Como, agora, fazer uso desses handlers? A biblioteca do glade para Python permite que isso
seja de forma fácil, atribuindo vários handlers a funções diferentes. Veja o código abaixo:
import sys
import pygtk
import gtk
import gtk.glade
class GladeTest:
def botao_clicked (self, widget):
print "botao clicado"
def __init__ (self):
self.wTree = gtk.glade.XML("project2.glade")
self.window = self.wTree.get_widget("window1")
dic = { "on_window1_destroy" : gtk.main_quit,
"on_botao1_clicked" : self.botao_clicked }
self.wTree.signal_autoconnect (dic)
gtk.main()
if __name__ == "__main__":
70
72. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasil/DF
glade_test = GladeTest()
Salve este código em um arquivo na mesma pasta do projeto Glade e execute-o. O resultado
é simples:
E como já deve ter sido possível perceber, o dicionário dic associa cada handler a uma função.
A função signal_autoconnect faz a associação automaticamente e de uma só vez.
10.3 Despedidas
Infelizmente o curso não irá se aprofundar mais do que isso em Glade, ficando isso a cargo
do leitor. Informações sobre Glade podem ser encontradas na Web; a página do próprio Glade é
um bom ponto de partida: http://glade.gnome.org/.
E com isso concluímos o curso. Boa parte da matéria foi vista, mas recomenda-se ao aluno
que nunca pare de aprender novas tecnologias e aprofundar-se nas existentes; busque cursos,
sites, leia, mas não fique parado!
Espero que tenham gostado!
71