Criando formulários com Python e PyGTK3

Criando formulários com Python e PyGTK3

09/03/2015 Pedro Jefferson 10 min de leitura

Introdução

Pygtk é uma camada Python construída sobre o Gtk. Gtk nada mais é que o Gimp Toolkit, biblioteca utilizada pelo GNOME na criação de interfaces.

Esse tutorial foi construído com base no Manual de Referencia do Gtk3 e no Python GTK+ 3 Tutorial.

Requisitos

  • Python 2.7.6 padrão (no Linux), em breve a versão 3 o substituirá.
  • Gtk3
  • Gdk
  • Sqlite3

Python

A maioria das distribuições Linux já contam com o Python e o Gtk instalados por padrão. Para verificar se sua distribuição conta com os pacotes necessários abra o terminal e digite:

python --version

Gtk

Para verificar se há bibliotecas Gtk instaladas em uma distribuição derivada do Debian, digite:

dpkg -l libgtk2.0-0 libgtk-3-0

Deve retornar algo do tipo: Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) ||/ Nome Versão Arquitectura Descrição +++-===============================-====================-====================-======= ii libgtk-3-0:amd64 3.14.8-0ubuntu1~14.0 amd64 GTK+ graphical user interface library rc libgtk-3-0:i386 3.14.8-0ubuntu1~14.0 i386 GTK+ graphical user interface library ii libgtk2.0-0:amd64 2.24.23-0ubuntu1.1 amd64 GTK+ graphical user interface library ii libgtk2.0-0:i386 2.24.23-0ubuntu1.1 i386 GTK+ graphical user interface library

Se você estiver utilizando uma distribuição derivada do Red Hat, digite:

yum list installed gtk3-devel gtk2-devel

O retorno a seguir mostra que os pacotes estão corretamente instalados:

Plugins carregados: auto-update-debuginfo, langpacks Pacotes instalados gtk2-devel.x86_64 2.24.26-1.fc21 installed gtk3-devel.x86_64 3.14.8-2.fc21 installed

Usuários de Mac OSX podem conferir este post.

Usuários Windows precisam baixar o interpretador Python aqui e o utilitário de instalação do PyGTK aqui.

Daqui em diante será mostrando o exemplo utilizando PyGtk. Logo abaixo é possível ver a importação das bibliotecas necessárias para construir a aplicação. Estas são as mesmas bibliotecas que foram verificadas anteriormente:

Conhecendo Gtk.Window

A princípio criei uma classe Janela que herda de Gtk.Window, essa será a janela principal. Logo em seguida, define-se o método construtor e todos os atributos da janela principal, como o título da janela, o tamanho padrão, se a tela vai ser redimensionada ou não, cor de fundo e etc. Veja no código a seguir.

No código acima, é instanciada a classe Gtk.Window e configurado os seus atributos, sendo eles o título da janela, tamanho da janela em pixels (600x600), configuração para não redimensionar a janela, e a cor de fundo da janela. O método modify_bg, que altera a cor da janela, recebe dois argumentos: um tipo de estado do gtk (StateType) e o color_parse com uma cor em Hexadecimal. Os estados possíveis que o modify_bg pode receber são: NORMAL, FOCUSED, ACTIVE, INCONSISTENT, INSENSITIVE, PRELIGHT e SELECTED, lembre-se, todos em maiúsculos. O que cada um estado representa? veja aqui.

Atenção, objetos do tipo Window só aceitam um objeto por vez. Para poder utilizar múltiplos objetos por vez é necessário utilizar objetos containers dentro da janela. Começaremos com um container grid, que agrupará outros widgets.

Gtk.Grid

A Grid é um elemento do tipo container que contempla vários widgets como entradas de texto, labels, botões e toda parte que se pode interagir com a aplicação. Você deve imaginar uma grid exatamente como uma tabela. Aqui são adicionadas duas grids. Dentro de uma grid, vai um elemento box1 que é um Gtk.Box que também é um objeto container. É completamente necessário adicionar a nova box de fato na grid utilizando o grid.attach. O grid.attach recebe 5 parâmetros, sendo a referência do objeto a ser adicionado (self), left, top, width e height.

Label

Labelinit é um objeto do tipo Label que é utilizado para textos, e que será o título da aplicação. Um dos mais interessantes métodos da classe label é o set_markup, pois ele recebe como argumento uma string formatada em pango markup language. Quer conhecer mais? Então clique aqui.

Mas lembre-se, apesar de ter uma sintaxe muito parecida, Pango não é HTML, portanto, nem todas as tags que você por funcionarão.

Box

A inserção de qualquer objeto em um elemento do tipo Box, se dá por dois comandos: Box.pack_start para adicionar objetos no início da box e Box.pack_end que obviamente adiciona objetos no fim da box. Os parâmetros informam se ele será expansível ou não, se terá preenchimento e espaço entre os objetos. Por fim, crio um novo objeto do tipo Grid, chamada de grid2 e passo a quantidade de espaço entre duas colunas consecutivas, espaço da coluna e espaço da linha. Confira Linha 34 do código anterior.

Com toda a estrutura da janela criada, vamos aos objetos!

Widgets

Widgets são objetos comuns de uma interface, como campo de entrada, textos, botões, caixa de seleção e etc. Eles obrigatoriamente devem ficar contidos em objetos containers, como Grids ou Box. O primeiro objeto é o label do nome, o set_halign representa o alinhamento horizontal do objeto em relação a grid ou box em que esse objeto está, da mesma forma temos set_valign para o alinhamento vertical. Eles recebem como parâmetro um objeto do tipo Gtk.Align, e os tipos são: BASELINE, CENTER, FILL, START. Dúvidas sobre os tipos? Veja mais aqui.

Em seguida, adicionamos na grid1 com left=0, top=1, width=1 e height=1. Objetos do tipo Gtk.Entry (Linha 39) são altamente configuráveis, no exemplo fi configurado o max_length para 150, que é o maior quantidade de caracteres que o campo pode receber, e o tamanho do campo width_chars em caracteres(30), note que um é completamente diferente do outro. Por fim, adicionei o objeto na grid2 e criei uma conexão.

Conexões

Conexão é, a grosso modo, a ligação do estado do objeto com um método. No exemplo, é criado uma conexão do estado “changed” com um método chamado “on_entry_nome_changed” , até então não criado ainda. Mas o que ela faz? Ela é chamada toda vez que o estado da entry_nome for mudada.

O que se segue agora é a repetição do código acima com apenas algumas modificações. Vamos criar um label e um entry para cada entrada que o usuário tiver que digitar. Note que, o objeto label é o texto que fica ao lado da área para o usuário digitar. E o objeto entry é justamente o campo.

A única diferença está no objeto entry_tel que chama o set_text para demonstrar como deve ser a entrada do telefone, e logo abaixo é configurada a cor cinza claro via Gdk._color_parse. (Linhas 63 e 64)

O mesmo acontece com as próximas entradas Email e Data de Nascimento.

Gtk.ComboBoxText

O Gtk.ComboBoxText é um meio de entrada de dados que utiliza uma lista já criada e recebe três parâmetros, um inteiro informando a ordem, um id e o texto.

Gtk.Button

Criei um objeto chamado commit do tipo Gtk.Button (Linha 110). Este objeto recebe como parâmetros: um label, um alinhamento, o posicionamento na grid, o tamanho do botão, e uma conexão usando o sinal “clicked”(com outro método que não está criado ainda).

Adicionando objetos containers no container principal

Por fim, vamos pegar todas as grids e box que criamos no meio do caminho e vamos amarrá-las à grid principal chamada grid_total (Linhas 121 e 122 do código abaixo).

Métodos

Vamos fazer dois métodos para o funcionamento do formulário. O primeiro método será on_entry_nome_changed para auxiliar na entrada do nome do usuário. A utilização deste método se deve ao fato dele colocar o nome em maiúsculo em tempo de execução. Funciona da seguinte maneira: O usuário coloca o nome e em tempo de execução, o método transforma os caracteres para maiúsculo, por isso é usado o sinal “changed”, pois a cada carácter novo o método precisa torná-lo maiúsculo. Então ele pega o texto via get_text e faz o upper, que torna-o maiúsculo e devolve o texto por outra função set_text. Confira no código abaixo.

O segundo método é o do botão de cadastro. Este é o momento de salvar os dados no banco.

Ele pega todos as entradas de todos os campos via get_text ou via get_active_text (para objetos ComboBoxText). Se não forem nulos, ele os envia para a função que de fato faz commit no banco de dados. Se todas as entradas forem informadas, o método commit_dados é chamado. Caso um dos campos for nulo ele executa o comando pass e não envia nada ao sqlite (Linhas 141 à 144 do código abaixo).

A função “commit_dados” recebe os parâmetros, cria uma conexão sqlite3 com um arquivo de banco de dados. A segunda linha do código é necessária para o sqlite possa processar texto do tipo 8-bits. É preciso também criar um cursor, pois é nele que vamos executar os comandos sql.

Passo todos os parâmetros em apenas dois comandos sql (Linhas 151 e 152), sendo que o primeiro verifica se o banco de dados já existe. Se não existir, ele cria o banco e o modelo, setando os tipos de dados e os nomes dos campos. O segundo insere os dados nos campos. Os dados são pegos pelos argumentos da função principal *args e são passados como símbolos(?) para cada campo inserido. Lembre-se que a quantidade de “?” tem que ser a mesma quantidade de parâmetros contido em *args. No final, executo uma função da conexão chamada commit que salva os dados no banco.

Cuidado para não confundir a função commit_dados do botão com a função do sqlite commit.

A última coisa a fazer é iniciar a aplicação…

Crio um objeto do tipo Janela(), que é a nossa janela principal. Utilizo o connect para criar uma conexão entre a janela principal e o sinal “delete-event” (que é o sinal de fechar a janela). O comando show_all exibe todos os widgets ligados a janela, seja grid, box, entry, comboboxtext, entre outros.

E por fim Gtk.main() inicia o gtk executando tudo.

Se você seguiu passo a passo a criação da aplicação essa deve ser a aparência final.

screen

Espero que você tenha gostado do mini-tutorial, e principalmente tenha aprendido algo, pois a intenção é justamente passar o conhecimento para frente! O código completo da aplicação você pode acessar clicando aqui.

No caso de dúvidas atendo pelos comentários desse post, pelo e-mail ou pelo Twitter.

Obrigado, e até mais!