Devido a uma pergunta interessante feito pelo Cassimiro Andrade aqui resolvi fazer este post mostrando como criar o programa com as funcionalidades sugeridas pelo Cassimiro no comentário.
Basicamente irei mostrar como criar um programa que irá modificar uma determinada palavra, e as opções de modificação desta palavra será definida por um radio button selecionado em um grupo de radio buttons.
Primeiramente tenha em mente que os passos descritos aqui foram realizados com a versão 3.12.1 do Glade e a versão 3.2 do Python.
Como estou utilizando o ubuntu 12.04 precisei instalar todos os componentes necessários, felizmente os mesmos estão disponíveis no próprio repositório do sistema, portanto basta executar os comandos abaixo para instala-los
# apt-get install python3 glade python3-gi
Caso esteja utilizando o fedora instale da seguinte forma
# yum install python3-gobject python3 glade
Uma vez que tenha tudo instado podemos começar criando a interface, abaixo segue como será a estrutura do programa criado no glade
Janela Principal - GtkWindow
`------- Divisão vertical com 4 partes - GtkBox
|
`------+ Quadro de Opções com a etiqueta Opções - GtkFrame
| `------------+ Caixa para os Radio Buttons - GtkButtonBox
| `------------------ 3 Radio Buttons - GtkRadioButton
|
`--------+ Quadro de inserção da palavra - GtkFrame
| `-------------- Entrada de texto - GtkEntry
|
`-------+ Caixa para adicionar o botão de processamento - GtkButtonBox
| `----------------- Botão de processamento - GtkButton
|
`---------- + Barra de rolagem - GtkScrolledWindow
`---------------- Área de visualização da palavra modificada - GtkTextView
Em imagem fica melhor não ?
Perceba na imagem acima as opções que estarão disponíveis no programa, nada muito complicado apenas simples manipulações de um texto como inverte-lo, criar anagramas ou deixar a palavra com letras maiúsculas ( a sugestão no comentário foi realizar um Capitalize na palavra mas eu preferi deixar todas as letras em maiúsculo do que apenas a primeira letra, é possível realizar Capitalize com o método "string".capitalize() no python).
Ok vamos começar a criar a interface no glade, inicie criando um top level window que será nossa janela principal e adicione um GtkBox separado em 4 partes conforme as imagens abaixo
Gtk Window |
GtkBox dividido em 4 partes |
Gtk Frames |
Agora vamos adicionar um GtkButtonBox com 3 campos no frame Opções que irá suportar os radio buttons, adicione no centro do frame onde está vazio conforme imagem abaixo
GtkButtonBox |
Adicione um GtkRadioButton em cada box do GtkButtonBox
GtkRadioButton(s) |
Note na imagem acima que os radio buttons estão todos ativos (selecionados) isso ocorre por que nenhum botão sabe da existência dos outros.
Para que apenas um radio button esteja ativo devemos agrupa-los para que todos os radio buttons se enxerguem, quando agrupamos radio buttons, definimos um dos botões como o grupo em si, basicamente este botão (o pai do grupo) será o que estará ativo quando o programa for executado pela primeira vez e obviamente os outros botões estarão desativados.
Devemos adicionar apenas os botões desativados ao grupo do botão pai que será o grupo em si, nesse caso iremos definir o radio button com o rótulo de Inverter como grupo logo não iremos mexer nele e sim nos outros botões restantes Anagrama e Letra Maiúscula.
Na aba geral desses botões clique na opção Grupo e na janela que abrir selecione o botão pai (radiobutton1 - Inverter) e clique em ok, faça este procedimento com o radio button Anagrama e Letra Maiúscula.
Observação: No momento que eu estava criando a interface eu não fui renomeando os widgets em cada passo e por isso os widgets estão com os nomes que são criado por padrão mas é uma boa pratica renomear os widgets com seus devidos nomes para você se organizar e não se perder, outro motivo para renomear os widgets é para poder obtê-los mais facilmente no seu código python.
Na imagem acima o widget radiobutton1 é o que está com o rótulo Inverter e deveria estar com o nome de inverter também.
Após agrupar os botões apenas o botão pai deverá estar ativo e na aba geral na entrada do grupo deverá constar o nome do grupo (botão pai == radiobutton1) como na imagem abaixo
Agora os radio buttons estão agrupados e conseguem se enxergarem, portanto ao selecionar um botão automaticamente os outros botões do grupo se desativarão.
Saindo um pouco do passo a passo, o Cassimiro fez esse comentário perguntou como ficaria a questão dos signals com um grupo de radio buttons, e essa é uma parte interessante do tutorial de se levantar essa questão, por que basicamente o programa terá um botão processar que quando clicado irá verificar qual dos radio button está ativo e efetuar seu determinado processo, indo direto ao ponto a identificação do botão ativo será realizada em código python onde nós iremos obter o widget do pai do grupo (radiobutton1 == Inverter) que consequentemente irá nos trazer as informações dos outros botões então o único signal necessário para o procedimento do programa será realizado por um outro botão único que iremos adicionar mais adiante. De qualquer forma as coisas irão ficar mais claro no código python do programa.
Continuando a criação da interface, agora adicione um GtkEntry no GtkFrame Palavra
GtkEntry |
E adicione um GtkButton no GtkBox que foi criado
GtkButton |
Na aba Geral do novo GtkButton altere o campo Rótulo para Processar
No último campo do GtkBox adicione um GtkScrolledWindow (Barra de rolagem)
GtkScrolledWindow |
Na aba Empacotamento do GtkScrolledWindow ative a opção Expandir para que ele ocupe todo o espaço disponível em seu campo no GtkBox
Dentro do GtkScrolledWindow insira o GtkTextView que será utilizado para exibir a palavra modificada
GtkTextView |
Agora para finalizar a criação da interface, vamos configurar os siginals necessários que serão apenas dois, o signal delete-event do widget da nossa janela principal que serve para finalizar o programa e o signal clicked do botão Processar que irá chamar uma função do código python e executar os procedimentos necessários.
Na aba Sinais do GtkWindow configure no setor GtkWidget o signal delete-event
Na aba Sinais do GtkButton Processar configure o signal clicked no setor GtkButton
Com isso a interface está basicamente pronta, basta salvar o trabalho em um arquivo .glade que toda a interface estará disponível em formato xml.
Antes de salvar o arquivo eu realizei algumas modificações como simples acabamentos, alinhei os labels no centro do programa, adicionei uma mensagem amigável no GtkEntry e defini um tamanho limitado de 10 caracteres para que palavras muito grandes não serem inseridas, o motivo é por que a função que utilizo para criar um anagrama da palavra irá gerar todas as combinações possíveis com os caracteres da palavra inserida o que pode gerar erros de memória caso a palavra seja muito grande.
Renomeei os widgets para que eu possa obtê-los mais facilmente através do python, não mostrei como fazer essas modificações por serem simples e o posto já está bem grande, mas são modificações simples que você pode realizar nas abas de gerenciamento dos widgets. No final do Post eu vou deixar um link com o arquivo .glade gerado neste tutorial.
Abaixo segue o código comentado do programa e mais adiante uma explicação mais detalhada da função que checa os radio buttons
#!/usr/bin/python3 from gi.repository import Gtk from itertools import permutations class ManageWord(object): def __init__(self): # Obtem uma Instância do Gtk.Builder e adiciona o arquivo .glade builder = Gtk.Builder() builder.add_from_file("radio_buttons.glade") # Obtendo os widgets self.window = builder.get_object("window") self.window.show() # GtkEntry onde será inserida a palavra self.word_entry = builder.get_object("word_entry") # GtkTextView que onde será exibido a palavra modificada self.text_view = builder.get_object("textview1") # Botão Processar self.button = builder.get_object("process_button") # Radio button com o rótulo Inverter que é o botão Pai self.inverter_radio = builder.get_object("inverter_radio") # Conectando os Sinais builder.connect_signals({ "gtk_main_quit": Gtk.main_quit, "process_button_clicked": self.process_option, "on_word_entry_activate": self.process_option }) # Métodos com as funções de modificação da palavra def invert_word(self, word): """ Inverte a palavra """ word = word[::-1] return word def get_anagram(self, word): """ Cria anagrams da palavra """ # Cuidado com essa função pois ela pode causar erros # de falta de memória pois gera todas as palavras possíveis anagrams = ["".join(anagram) for anagram in permutations(word)] # Retorna somente as primeiras 100 palavras return anagrams[:100] def get_active_radio(self): """ Verifica qual Radio Button está ativo""" # Obtem uma lista com os radio buttons que pertencem ao grupo radio_buttons = self.inverter_radio.get_group() # Percore a lista de botões e verifica qual botão está ativo for radio in radio_buttons: # check if option is activated if radio.get_active(): # Retorna o Rótulo do Radio Button que está ativo return radio.get_label() def process_option(self, widget): """ Executa a modificação da palavra baseado na opção ativa """ # Obtem a palavra que foi inserida pelo usuário word = self.word_entry.get_text() # Obtem o campo de inserção onde a palavra modificada será exibida text_buffer = self.text_view.get_buffer() option = self.get_active_radio() # Verifica a opção escolhida e executa o procedimento necessário if option == "Inverter": output = self.invert_word(word) elif option == "Anagrama": # Obtem uma lista com os anagramas list_output = self.get_anagram(word) # Cria uma string com todos os elementos da lista output = "" for line in list_output: output += line + "\n" elif option == "Letra Maiúscula": output = word.upper() # Inseri o texto modificado no GtkTextView text_buffer.set_text(output) if __name__ == "__main__": # Instância da classe do programa app = ManageWord() # Loop para o programar continuar rodando até o usuário fecha-lo Gtk.main()Com o código acima e o arquivo .glade no mesmo diretório podemos executar o programa
# De permissão de execução
chmod +x radio_buttons.py
# Execute
./radio_buttons.py
Programa em execução |
Invertendo a palavra |
Criando Anagramas |
Deixando as letras maiúsculas |
O arquivo .py e .glade criados nesse post podem ser baixados aqui
def get_active_radio(self): """ Verifica qual Radio Button está ativo""" # Obtem uma lista com os radio buttons que pertencem ao grupo radio_buttons = self.inverter_radio.get_group() # Percore a lista de botões e verifica qual botão está ativo for radio in radio_buttons: # check if option is activated if radio.get_active(): # Retorna o Rótulo do Radio Button que está ativo return radio.get_label()
Essa função é utilizada para obter o radio button que está ativo no momento em que o botão Processar do programa é pressionado, ela utiliza o objeto inverter_radio definido no constructor da classe, como esse objeto é o grupo (botão pai) dos radio buttons ele traz consigo uma referência dos outros botões por isso podemos obter uma lista de todos os botões do grupo com o método .get_group() da instância deste widget.
Veja abaixo um exemplo prático executado no shell python
>>> from gi.repository import Gtk >>> builder = Gtk.Builder() >>> builder.add_from_file("radio_buttons.glade") 1 # aqui eu obtenho o widget inverter_radio que é grupo >>> inverter_radio = builder.get_object("inverter_radio") # utilizo o método .get_group() que irá me retornar uma lista com todos # os botões do grupo >>> radio_group = inverter_radio.get_group() >>> len(radio_group) 3 # Cada elemento do grupo é um radio button porém representado como um objeto # do python e seu endereço único na memória >>> radio_group [<RadioButton object at 0x1188550 (GtkRadioButton at 0x154e2e0)>, <RadioButton object at 0x1188730 (GtkRadioButton at 0x154e170)>, <RadioButton object at 0x11880f0 (GtkRadioButton at 0x154e000)>]# Cada radio button tem um método .get_name() que em teoria deveria retornar # o nome definido no glade mas retorna a classe >>> radio_group[0].get_name() 'GtkRadioButton' # Felizmente o método .get_label() retorna corretamente o Rótulo do radio button >>> radio_group[0].get_label() 'Letra Maiúscula' # Com o método .get_active() retornando True ou False podemos verificar # se o botão está ativo (selecionado) >>> radio_group[0].get_active() False # Com esse métodos podemos verificar qual botão está ativo e obter seu rótulo >>> for button in radio_group: ... print(button.get_label(), button.get_active()) ... Letra Maiúscula False Anagrama False Inverter True >>>
O GtkRadioButton possuí um signal chamado toggled na seção GtkToggledButton, que é disparado toda vez que determinado botão for ativado, nesse programa seria possível configurar esse signal para que quando um radio_button for selecionado imediatamente chamaria uma função que iria armazenar o nome ou rótulo do radio button em uma variável global e dessa forma já saberíamos qual opção foi escolhida, porém trabalhar com uma variável global que fica mudando aleatoriamente desta forma não é considerado uma boa prática.
Basicamente é isso espero que esse post possa ajudar alguém e principalmente sanar a dúvida do Cassimiro Andrade.