quinta-feira, 18 de setembro de 2008

Continue mantendo sua sanidade com o Glade

.
Pra quem está começando a trabalhar com GTK e GLADE, recomendo a leitura do excelente tutorial de Marcelo Lira, "Mantendo A Sanidade Com O Glade". Ele dá uma visão completa de todo o processo, desde o desenho da interface no GLADE até a compilação final, com exemplos em várias linguagens.

O objetivo deste texto é complementar este tutorial, mostrando alguns problemas que aparecem no desenho da interface no GLADE, e as soluções que encontrei. Infelizmente este texto não é lá muito “básico”... será preciso algum conhecimento de GTK e até do próprio GLADE. Espero que seja útil mesmo assim. Outros textos introdutórios de GTK virão por aí em algum momento no futuro.

Criaremos com o GLADE a seguinte caixa de diálogo:


Uma caixa de diálogo em GTK possui 2 áreas: uma superior, onde colocaremos nossos widgets, e outra inferior, com espaço para os botões. Podemos começar, então, inserindo no GLADE uma dialog box:


Qual gerenciador de layout colocaremos na parte superior? Vamos analisar nossa interface: ela está mais ou menos organizada “por linhas”, como, por exemplo, a primeira linha (label “tipo de servidor” e drop-down para a escolha do tipo de servidor), ou a última linha (botão “listar bancos de dados”, e drop-down para escolher o banco de dados). Para organizar em linhas, utilizaremos então uma “vbox”.

Agora, outra dúvida: quantas linhas teremos na vbox? Vemos 3 linhas óbvias (primeira, “tipo de servidor”; penúltima, “usuário e senha”; e última, “listar bancos de dados”). Mas, e quanto a localização do servidor? Serão mais 3 linhas?

Na verdade, configura apenas mais 1 linha, pois as 3 linhas que vemos ("endereço ip", "nome" e "nesta máquina") estão AGRUPADAS dentro de um único widget, chamado frame (“localização do servidor”). Precisaremos então de apenas mais uma linha, para inserir a frame. Dentro da frame, aí sim, teremos que criar 3 linhas.

Vemos então na figura abaixo, nossa interface com a vbox configurada para 4 itens:


A primeira linha possui 2 widgets, organizados horizontalmente. Logo utilizaremos uma hbox, com 2 espaços disponíveis.

Na segunda linha, como já falamos, colocaremos uma frame.

Na terceira linha teremos 4 widgets, também organizados horizontalmente. Usaremos então uma hbox de 4 itens.

Finalmente, a última linha terá 2 itens, organizados horizontalmente. Nova hbox, de 2 itens.

Nossa interface fica como apresentado na figura abaixo:


Vamos pensar um pouco como ficará o interior da nossa frame na linha 2. Podemos pensar numa organização também por linhas, mas se olharmos mais atentamente poderemos perceber a existência de linhas E colunas (temos uma coluna de radio buttons, e outra de dados extras, ligados a esses radio buttons). Assim, ao invés de usar uma vbox, usaremos uma table, com 3 linhas e 2 colunas. Nossa interface fica como na figura abaixo:


Ainda sobre esta tabela, notemos a área localizada na primeira linha, segunda coluna: aqui teremos um conjunto de 7 widgets, composto por caixas de texto e labels (pontos), organizados horizontalmente. Vamos inserir então a última hbox de nossa interface, com 7 itens.


Agora que o layout da interface está planejado, podemos inserir seus diversos widgets (labels, caixas de texto, botões, drop-down). Apenas inseri os widgets, colocando os textos corretos, sem mexer ainda em outras configurações. Nesse momento, algo estranho acontece: a janela cresce demais! Se fizermos um teste de apresentação real da janela (usando libglade), vemos que ela está longe de ser visualmente agradável:

Glade:

Programa compilado:

Vamos começar então a “arrumar a casa”. O primeiro problema é o tamanho default das caixas de texto. Na linha do “endereço ip”, cada caixa só precisa armazenar (e exibir) no máximo 3 caracteres. Para as outras, vamos definir exibição de 10 caracteres. A propriedade “maximum length” define o número máximo de caracteres que a caixa poderá armazenar, e a propriedade “width in chars” é o tamanho (em caracteres) da caixa.

Outro problema está relacionado a configuração de expansão dos widgets. Por default, está definido que cada widget vai expandir e ocupar todo o espaço livre disponível. Note na figura acima, por exemplo, a primeira linha (“tipo de servidor”). Como todo o diálogo está aumentado por causa das caixas de texto, o gerenciador de layout dividiu o espaço extra igualmente pelo label “Tipo de servidor” e o drop-down ao seu lado. Precisamos, portanto, desligar a propriedade “expand” de alguns widgets. Cada caso é um caso, mas podemos ter como regra geral fazer isso nos widgets “da esquerda”, e em especial nos labels. Se sobrar espaço na direita, deixamos as caixas de texto e drop-down ocuparem o espaço extra.

Assim, desligaremos a propriedade “expand” dos seguintes widgets:

- label “Tipo de servidor”;
- radio “endereço ip”;
- labels dos pontinhos no endereço ip;
- radio “nome”;
- radio “nesta máquina”;
- label “usuário”;
- label “senha”;
- botão “listar bancos de dados”.

Após essas alterações, o GLADE continuou mostrando o diálogo aumentado (pelo menos no meu caso). Também não consegui diminuir seu tamanho arrastando as bordas. Neste momento fechei o projeto e reabri, e aí sim, ele mostrou o diálogo no seu novo tamanho real. De qualquer modo, é sempre bom ir testando “ao vivo”, através de um programa. Como a interface é desenhada “na hora” (dinamicamente), não precisa nem recompilar, basta salvar o arquivo .glade e rodar o programa para ver o resultado. O estado atual de nossa interface é apresentada na figura abaixo:


Bem melhor, não é? Agora só precisamos passar um “pente fino”. Vamos colocar um espaço após os dois-pontos dos labels “Tipo de servidor” e “usuário”, para aumentar a separação entre eles e o widget ao seu lado. No label “senha”, vamos colocar um espaço antes da palavra e outro depois dos dois-pontos. Vamos também colocar um espaço antes e outro depois do texto no botão “Listar bancos de dados”. Vamos aproveitar e tirar os dois-pontos depois do label “nesta máquina” ( só vi o erro agora... :-) )


As “linhas” que compõem a interface estão muito apertadas, muito próximas umas das outras. Vamos então aumentar o espaçamento entre elas. Lembra da vbox que inserimos no início do processo? Vamos aumentar a propriedade “spacing” para 6:


Note que o conteúdo da frame não foi espaçado, pois está todo em apenas uma “célula” da vbox. Para espaçar este conteúdo, precisamos alterar a propriedade “row spacing” da tabela que inserimos na frame. Coloquei o valor 4. Ainda na frame, podemos ligar o contorno, para desenhar uma caixa. Para isso, vamos alterar a propriedade “frame shadow”, colocando “etched in”.


Podemos notar mais 2 probleminhas dentro da frame: o primeiro é que todos os radio buttons estão ativos! Isso acontece porque o GTK não sabe que eles pertencem a um mesmo grupo, ele acha que são 3 radios separados! Para resolver este problema é preciso estabelecer uma ligação entre eles. Para isso, alteramos a propriedade “group”. Por exemplo, vamos no radio “nome”, e na propriedade group marcaremos o radiobutton1 (“endereço IP”). Faremos o mesmo com o radio “nesta máquina”. Resumindo: radiobutton2 e radiobutton3 fazem referência a radiobutton1, e com isso, todos os 3 ficam no mesmo grupo.

O segundo problema é estético: há um espaço grande, no lado esquerdo da frame, e um espaço mínimo no lado direito (ambos por dentro da frame). Isto pode ser ajustado através das propriedades “left padding” e “right padding” do widget “alignment” (é um dos widgets que compõem a frame). Colocaremos o valor 6 tanto na direita como na esquerda.

Uma última coisa a ser feita, definir o título da janela, na propriedade “window title” do diálogo.


Prontinho! Não esqueça de definir os nomes das callback functions nos widgets correspondentes.

A propósito... tive um problema ao tentar utilizar a função glade_xml_signal_autoconnect (liga automaticamente os eventos gerados pelos widgets às funções callback que definimos no nosso programa principal), pois o programa que estou fazendo é um “híbrido” C/C++. Estou programando em C, usando GTK em C, porém também preciso usar uma biblioteca específica (TerraLib) feita em C++. Logo, estou compilando em C++, e por causa de características específicas desta linguagem acerca de nomes de funções, o autoconnect não consegue encontrar as funções callback. A solução é bem simples: basta definir as funções como “extern C”, assim:

extern "C" void bot_conct(GtkButton *bt, GtkWidget *win)
{
printf("teste...");
getchar();
}

Também precisa adicionar a opção -rdynamic ou -export-dynamic no linkeditor.

Bem, é isso aí. Não deixem de comentar com dúvidas e/ou correções.

Abraços a todas e a todos!
Carlão

5 comentários:

Setanta disse...

bom trabalho :)

Diogo_RBG disse...

extern "C" era justamente o que eu procurava ! vlw msm !

Berg disse...

Rapaz, muito bom!
A gente devia tentr colocar o material sobre o Glade 3 mais pra frente mesmo. Afinal Interface gráfica é algo que mais do que importantes principalmente pra uqme tá aprendendo a programar.

Carlos José disse...

Oi Berg,

Fique de olho, em breve mais material sobre gtk, glade e colaboração com o projeto gnome!

Abraços!
Carlão

Anônimo disse...

EU GOSTARIA MUITO DE APRENDER A PROGRAMAR EM GLADE. IRIA FAZER VÁRIAS GUI PARA APLICATIVOS LINUX.