Anda di halaman 1dari 17

Iniciando-se no GTK

1. Introduo 1. O que o GTK/GTK+ 2. O que um widget 3. Questes prticas 2. Primeiros passos 1. O primeiro programa 2. Como compilar 3. Sinais e "callbacks" 4. Entendendo os widgets 5. Packing Widgets

Introduo
A interface visual sem dvida um dos principais aspectos de um programa. Para determinados usurios, uma interface grfica pode ser indispensvel. Para outros, no mnimo desejvel. Por isso, os programadores precisam conhecer uma ferramenta de programao capaz de gerar interfaces amigveis, como o GTK. Este foi originalmente concebido em C, para ser usado na plataforma Linux, e muito fcil de ser usado. Para a plena compreenso do contedo deste tutorial, supomos que o leitor possua conhecimentos bsicos de C.

O que o GTK ? GTK uma abreviao para GIMP Tool Kit. O GIMP (GNU Image Manipulation Program) um poderoso editor grfico, ao estilo do Adobe Photoshop, com licena GPL, o que significa que ele gratuito, e pode ser distribudo livremente. O GTK tem esse nome pois foi originalmente concebido para servir de ferramenta no desenvolvimento do GIMP. Devido a versatilidade das funes do GTK, hoje este utilizado na produo de diversos outros programas alm do GNU Image Manipulation Program, que variam desde pequenos utilitrios, como o GTK-ICQ, at grandes projetos, como o gerenciador de Desktop GNOME. O GTK na verdade um conjunto de widgets (voc ver o significado desta palavra mais adiante), que usa funes de outra biblioteca chamada GDK (GIMP Drawing Kit), que por sua vez um conjunto de funes que chamam

outras funes de baixo nvel do ambiente grfico em que o programa compilado. Todo o conjunto do GTK ainda depende de uma biblioteca chamada GLib (GNU Library) de funes teis, comuns a vrios programas GNU, e que aumentam portabilidade. Existem interfaces de GTK para vrias linguagens, embora este documento trate apenas da verso para C. Programar em GTK exige o entendimento de conceitos de orientao a objetos, que no so to complicados para quem no conhece nada deste estilo de programao, e ainda servem como uma boa introduo para o assunto. Links interessantes: - www.gtk.org - www.gimp.org - www.gnome.org

O que um widget ? Um widget (literalmente, buginganga) um objeto importante ao layout da aplicao, e a estrutura fundamental dos programas em GTK. A maioria dos widgets so objetos grficos como janelas, botes, listas e figuras. Outros so invisveis, mas permitem controlar coisas como o alinhamento de outros widgets na tela. A grande maioria das funes no GTK serve para manipular os widgets de alguma forma.

Questes prticas Onde conseguir o GTK. Como instal-lo e verificar se est funcionando adequadamente ? A principal e mais confivel fonte para se obter o GTK com certeza o site do prprio (www.gtk.org) na seo de downloads. De qualquer maneira, o GTK est includo em todas as principais distribuies de Linux. Se voc deseja apenas saber se o GTK est instalado no seu sistema, experimente digitar "gtk-config --version". Se tudo estiver correto, voc ver a verso do GTK instalada no seu sistema. Se no, voc deve procur-lo e instal-lo.

Para usurios da RedHat, o GTK esta disponvel nos seguintes pacotes RPM: - gtk+-(verso do pacote).rpm - contm as bibliotecas usadas pelo programa - gtk+-devel(verso do pacote).rpm - contm os arquivos necessrios para desenvolver seus programas com GTK. O programa gtk-config, que distribudo junto com o GTK, tem muitas utilidades alm de mostrar a sua verso da biblioteca. Digitando apenas gtkconfig, voc pode ver opes deste comando. Duas dessas opes sero realmente teis mais adiante quando comearmos a por a mo no cdigo.

Primeiros passos

O primeiro programa Nesta seo, vamos ver um primeiro exemplo da programao com GTK, entend-lo, e estende-lo at que tudo esteja pronto para entendermos algo mais complicado. Este primeiro, mas importante passo nada mais nada menos que o popular 'Al Mundo' em sua verso para GTK. O cdigo a seguir no faz muito alm de mostrar uma janela vazia com o ttulo 'Alo Mundo'.

/* Primeiro Exemplo - Alo Mundo - alo.c */ #include <gtk/gtk.h> int main(int argc, char **argv) { GtkWidget *janela; gtk_init(&argc, &argv); janela = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW (janela), "Alo Mundo"); gtk_widget_show(janela); gtk_main(); return 0; } /* Fim do Primeiro Exemplo */

Compilando... Para compilar o programa acima usando o gcc, podemos usar uma linha de cdigo como esta: $ gcc -o alo alo.c -Wall -g `gtk-config --cflags --libs` Novamente vemos o programa gtk-config sendo usado para algo extremamente til. Colocar este comando entre crases (ateno, use crases, e no o acento agudo) faz com que aquilo que o programa imprimiria na tela seja adicionado linha do compilador. Para entender melhor digite: $ gtk-config --cflags $ gtk-config --libs A primeira linha retorna os diretrios onde esto cabealhos de funes necessrios, enquanto a outra mostra a localizao das bibliotecas e quais so usadas pelo GTK. Desta maneira voc no precisa se preocupar com todos estes pequenos detalhes na hora de compilar o seu programa. Agora possvel compilar nosso primeiro exemplo e ver o que acontece. Ao executar o programa, repare que o nico jeito de encerr-lo matando o processo no console, digitando CTRL + C ou algo similar. Para saber mais sobre o compilador gcc, consulte a seo 1.4.1.

Entendendo o exemplo... * #include <gtk/gtk.h> Isto vai incluir o cabealho principal do GTK, que est em um subdiretrio chamado gtk no local padro dos includes (normalmente /usr/include ou /usr/local/include).

* GtkWidget *janela; Precisamos declarar um ponteiro para um widget que guardar uma referncia para o nico widget do nosso programa: a janela.

* gtk_init(&argc, &argv); Esta funo essencial em todos os programas feitos com GTK e o exemplo no ir rodar sem que ela tenha sido chamada no incio da execuo. Seu objetivo preparar variveis importantes ao GTK e avaliar os argumentos passados na linha de comando para procurar por algumas opes prdefinidas.

* janela = gtk_window_new(GTK_WINDOW_TOPLEVEL); A funo gtk_window_new() cria uma nova janela na memria e retorna um ponteiro para esta janela, para que ela possa ser manipulada por outras funes. O parmetro passado o tipo de janela a ser mostrada. Existem trs tipos de janela enumeradas no arquivo gtkenums.h. O tipo TOPLEVEL o mais importante, e onde a aplicao deve ser desenvolvida. Mais tarde iremos voltar a este assunto e veremos os dois outros tipos de janelas.

* gtk_window_set_title( GTK_WINDOW (janela), "Alo Mundo"); Esta linha muda o titulo da nossa janela, que pelo padro o nome do programa compilado, para "Alo Mundo". O primeiro parmetro um ponteiro para a janela em questo, e o segundo uma cadeia de caracteres (string) com o novo titulo. GTK_WINDOW() uma macro, com o objetivo de fazer a converso de um ponteiro para um widget, para um ponteiro para janela, pois este o tipo esperado pela funo. O GTK dispe de vrias macros com funo de converter entre tipos de variveis, e estas sero vistas um pouco mais adiante.

* gtk_widget_show(janela); gtk_widget_show() uma funo que espera como nico parmetro, um ponteiro para um widget, neste caso, a janela, que deve ser mostrado na tela.

* gtk_main(); Com esta funo o programa entra em um loop e espera por sinais do usurio como teclas pressionadas no teclado ou movimentos do mouse. necessrio

avisar ao programa o que fazer quando receber um destes sinais, e este justamente o prximo assunto.

Observao: bem fcil perceber que o GTK possui um nmero enorme de funes e que nem sempre possvel guardar todos os seus nomes e os parmetros necessrios para cada uma. Uma boa noticia que os nomes das funes do GTK so muito regulares. Como regra, todas as funes que manipulam um tipo de widget ou objeto do GTK seguem o padro abaixo: gtk_{nome do objeto ou widget}_{ao a ser realizada}(parmetros) Alm disso, muitos widgets compartilham aes entre si. Por exemplo: gtk_window_new() gtk_button_new() gtk_label_new() Estas funes criam uma janela, um boto, e uma etiqueta, respectivamente, retornando ponteiros para esses widgets. As macros de converso de tipo do GTK tambm seguem um padro: GTK_{TIPO} (objeto) Estas macros checam se o objeto pode ser convertido para o tipo especificado e em seguida fazem a converso.

Sinais e funes de "callbacks"


Como mencionamos antes, durante o loop gtk_main() os widgets comeam a receber sinais que so enviados pelo usurio, e estes podem vir de vrias fontes. Para tornar o programa mais interativo, necessrio escrever funes que respondam a estes sinais e acrescentar ao cdigo algo que diga ao programa como relacionar um sinal a aquela funo. Isto pode ser feito com a funo gtk_signal_connect(), e mostraremos o seu uso no prximo exemplo.

/* Segundo Exemplo - Alo Mundo 2 - alo2.c */ #include <gtk/gtk.h> void sair(GtkWidget *w, gpointer p) { gtk_main_quit(); } void clique(GtkWidget *w, gpointer p) { g_print("O botao foi clicado\n"); } int main(int argc, char **argv) { GtkWidget *janela, *botao; gtk_init(&argc, &argv); janela = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW (janela), "Alo Mundo"); gtk_signal_connect(GTK_OBJECT (janela), "destroy", GTK_SIGNAL_FUNC (sair), NULL); botao = gtk_button_new_with_label("Clique aqui"); gtk_container_add(GTK_CONTAINER (janela), botao); gtk_signal_connect(GTK_OBJECT (botao), "clicked", GTK_SIGNAL_FUNC (clique), NULL); gtk_widget_show(botao); gtk_widget_show(janela); gtk_main(); return 0; } /* Fim do Segundo Exemplo */ Vamos agora entender as modificaes feitas no programa. * void sair(GtkWidget *w, gpointer p);

Criamos esta funo para responder ao sinal de destruio da janela. Este sinal normalmente ocorre quando pressionamos o boto do mouse sobre algum boto na barra de ttulo do programa que fecha a janela. O cdigo desta funo simplesmente chama a funo do GTK gtk_main_quit(), que sai do loop gtk_main() e continua com o cdigo do programa. No nosso caso, aps a chamada de gtk_main() o programa retorna o controle ao sistema operacional.

Precisamos, no entanto, conectar esta funo ao sinal de destruio da nossa janela. ento que entra a funo gtk_signal_connect(), que recebe 4 parmetros simples: gtk_signal_connect(GtkObject *object, gchar *name, GtkSignalFunc func, gpointer func_data); object - O objeto que recebe o sinal. Como o parmetro esperado do tipo GtkObject, a macro GTK_OBJECT usada, para fazer a converso do widget janela. name - Uma string com o nome do sinal esperado. Neste caso, "destroy" um sinal recebido pela janela quando a mesma est para ser fechada. Existem vrios sinais definidos no GTK para cada tipo de widget. Veremos outros tipos de sinais ao longo do texto. func - Um ponteiro para a funo que vai responder ao sinal em questo. Lembre-se que em C o nome da funo um ponteiro para ela. Esta funo deve ter um prottipo do tipo: void callback_func(GtkWidget *widget, gpointer callback_data); GTK_SIGNAL_FUNC uma macro que faz a converso da funo para este padro. func_data - Este um parmetro passado para a funo de callback, cujo propsito depende unicamente do programador.

* botao = gtk_button_new_with_label("Clique aqui"); Esta linha cria um boto com o texto "Clique aqui" sobre ele, que pode responder ao evento de clique do mouse. Analogamente janela, conectamos a funo clique ao sinal "clicked" no boto. Perceba o uso de uma funo g_print() neste callback. Esta funo age

de maneira semelhante a printf() e pode ser usada para imprimir mensagens no console enquanto, a janela do programa ainda est aberta.

* gtk_container_add(GTK_CONTAINER (janela), botao); Isto faz com que o widget boto seja inserido dentro do container (recipiente) janela. Container uma classe seleta de widgets que podem conter outros widgets, e por isso a macro de converso usada.

Observao: * gtk_widget_show(botao); * gtk_widget_show(janela); Perceba a ordem em que os widgets so exibidos. Isso no meramente por acaso, mas para garantir que quando a janela (que contm todos os outros widgets) aparea, os outros objetos j estejam preparados e sejam mostrados juntos na tela. Assim, evitamos que uma mquina que no seja rpida o suficiente mostre os widgets aparecendo um por um na janela.

Entendendo os Widgets
Como voc j deve ter percebido, programar com GTK exige lidar com um nmero enorme de novas funes. Talvez at mais funes do que voc esteja normalmente acostumado a usar em seus programas. Entretanto, tambm fcil perceber que as funes do GTK so extremamente regulares. Inicialmente, todas as funes do pacote GTK comeam com 'gtk_'. Em seguida, o nome da estrutura a ser manipulada ('widget', 'button', 'box', etc), e por ltimo, a ao a ser realizada ('new', 'set_title', 'show', etc). Assim podemos admitir de agora em diante que para criar um novo widget, no importando o seu tipo, basta chamar a funo: * gtk_{tipo de widget}_new (); Alguns widgets podem ter mais de uma funo para cri-los. Um exemplo j conhecido o boto. Podemos criar um boto vazio com gtk_button_new() ou um que j possua uma etiqueta com gtk_button_new_with_label();

Outro tipo de funes bem recorrentes so aquelas que lidam com propriedades dos widgets, como gtk_window_set_title() para designar um ttulo a uma janela, ou gtk_widget_set_usize() para redimensionar um widget. Estas funes levam como parmetro o widget sendo manipulado e os novos atributos (uma string no caso do ttulo, ou dois inteiros no caso das dimenses). Macros de Converso de Tipo Nas chamadas a funes do GTK que recebem widgets como parmetros, muitas vezes estes devem ser de um tipo especfico, como container, ou box, ou window. De uma forma geral, o nome da funo j avisa qual ser o tipo de parmetro necessrio. Por exemplo, gtk_table_attach() precisa de um parmetro do tipo GtkTable, mas como declaramos todos os nossos widgets como GtkWidget, precisamos convert-los para o tipo correto com a macro GTK_TABLE(). Ao longo deste texto j vimos outros exemplos de macros de casting como GTK_BOX(), GTK_CONTAINER() e GTK_OBJECT(). O que estas macros realmente fazem verificar se possvel fazer o casting da varivel para o tipo desejado, e se for, faz-lo. Os widgets no GTK esto todos em uma hierarquia, como objetos. Existem tipos mais genricos e outros mais especficos. O tipo GtkObject est no topo da hierarquia, e GtkWidget est logo abaixo. Em orientao objetos dizemos que GtkWidget herda de GtkObject, porque todo GtkWidget um GtkObject, mas nem todo GtkObject um GtkWidget. Isto significa que a estrutura GtkWidget possui todos os campos da estrutura GtkObject, e possvel ver um widget como um object com alguns detalhes a mais. Por isso possvel o casting de GtkWidget para GtkObject. Mais adiante, veremos novos widgets, e entenderemos a sua posio na hierarquia dos widgets.

Packing Widgets
Como voc deve ter percebido pelo exemplo anterior, quando um widget colocado em um container (neste caso, o boto posicionado na janela), este geralmente tenta ocupar todo o espao disponvel. Para conseguir colocar mais de um widget em um container e ter um controle maior sobre o seu posicionamento preciso entender o conceito de empacotamento de widgets.

Existe mais de uma maneira de se empacotar um widget, entretanto elas so bem parecidas, e intuitivas de forma geral. Existem alguns tipos especiais de widget chamados caixas. Um widget caixa invisvel at que algo seja colocado no seu interior. A caixa possui subdivises para que voc possa colocar mais de um widget dentro dela.

Empacotando com caixas Para empacotar widgets em um container, primeiro criamos uma nova caixa com a funo correta. Por exemplo: * GtkWidget *gtk_hbox_new(gint homogeneous, gint spacing); A funo acima cria uma caixa horizontal com os dois parmetros passados e retorna um ponteiro para a mesma. O primeiro parmetro esperado (homogeneous) deve ser do tipo booleano (o GTK possui os valores TRUE e FALSE definidos) e determina se todos as subdivises da caixa tero o mesmo tamanho. O parmetro spacing um inteiro que define o espaamento em pixels entre um objeto e outro na caixa. Analogamente existe uma funo que cria caixas verticais, e que usa os mesmos parmetros do exemplo acima: * GtkWidget *gtk_vbox_new(gint homogeneous, gint spacing); Aps criada, uma caixa pode ser preenchida com vrios tipos de widgets (inclusive outras caixas). Isto feito com as funes abaixo: * gtk_box_pack_start(GtkBox *box, GtkWidget *child, gint expand, gint fill, gint padding); * gtk_box_pack_end(GtkBox *box, GtkWidget *child, gint expand, gint fill, gint padding); Ambas possuem os mesmos parmetros, mas fazem coisas diferentes ao empacotarem um widget. A primeira funo, gtk_box_pack_start(), coloca o widgets da esquerda para direita em um caixa horizontal, e de cima para baixo em uma vertical. A outra, gtk_box_pack_end(), faz tudo no sentido inverso, da direita para a esquerda na horizontal e de baixo para cima na vertical. O parmetro expand booleano e determina se o espao ao redor do widget sendo inserido vai se expandir para ocupar toda a sua parte da caixa ou se esta vai reduzir-se at ficar do tamanho do widget.

O parmetro fill informa se o widget vai ocupar todo o espao ao seu redor, ou se este vai ficar vazio servindo como espaamento. Repare que s h espao em volta do widget se o parmetro expand for TRUE ou se a caixa foi criada com o parmetro homogeneous TRUE, logo a opo fill s tem sentido se uma destas condies for satisfeita. O parmetro padding um inteiro que determina o espao mnimo em pixels entre o objeto e a borda da caixa. Abaixo veremos um exemplo sobre o empacotamento de widgets com caixas horizontais: /*** Terceiro Exemplo - Caixas Horizontais ***/ #include <gtk/gtk.h> void clique(GtkWidget *widget, gpointer data) { g_print("%s foi clicado!\n", (char *)data); } void sair(GtkWidget *widget, gpointer data) { g_print("Saindo...\n"); gtk_main_quit(); } int main(int argc, char **argv) { GtkWidget *janela, *caixa, *boto; gtk_init(&argc, &argv); janela = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT (janela), "destroy", GTK_SIGNAL_FUNC (sair), NULL); caixa = gtk_hbox_new(TRUE, 10); gtk_container_add(GTK_CONTAINER (janela), caixa); boto = gtk_button_new_with_label("Boto 1"); gtk_signal_connect(GTK_OBJECT (boto), "clicked", GTK_SIGNAL_FUNC (clique), "boto 1"); gtk_box_pack_start(GTK_BOX (caixa), boto, FALSE, TRUE, 0); gtk_widget_show(boto); boto = gtk_button_new_with_label("Boto 2"); gtk_signal_connect(GTK_OBJECT (boto), "clicked",

GTK_SIGNAL_FUNC (clique), "boto 2"); gtk_box_pack_start(GTK_BOX (caixa), boto, FALSE, TRUE, 0); gtk_widget_show(boto); gtk_widget_show(caixa); gtk_widget_show(janela); gtk_main(); return 0; } /*** Fim do Terceiro Exemplo ***/ Vamos agora revisar as novas linhas de cdigo: * caixa = gtk_hbox_new(TRUE, 10); * gtk_container_add(GTK_CONTAINER (janela), caixa); Nestas linhas criamos uma nova caixa com homogeneous igual a TRUE e 10 pixels de spacing entre os objetos da caixa. Em seguida adicionamos a caixa janela * boto = gtk_button_new_with_label("Boto 1"); * gtk_signal_connect(GTK_OBJECT (boto), "clicked", GTK_SIGNAL_FUNC (clique), "boto 1"); * gtk_box_pack_start(GTK_BOX (caixa), boto, FALSE, TRUE, 0); Criamos um boto com a etiqueta "Boto 1" e adicionamos o sinal de clique do mouse sobre ele. Repare que agora passamos o ltimo parmetro da funo gtk_signal_connect como "boto 1" ao invs de NULL. Este um dado que est sendo passado para a funo de callback clique() como o gpointer "data". Em seguida, adicionamos o boto a caixa com a funo gtk_box_pack_start, fazendo com que estes preencham todo o espao ao seu redor (parmetro fill igual a TRUE). Observao: Um detalhe importante deste programa que usamos um nico ponteiro chamado boto para criar dois widgets do tipo boto. Isto uma tcnica muito til especialmente para economizar variveis quando seu programa se torna grande. No processo de criao de uma varivel widget, escolhemos as suas propriedades, ligamos as funes de callback desejadas, o colocamos em um container, e usamos a funo gtk_widget_show() para mostr-lo na tela. Apenas tenha em mente que aps passar por estas etapas, a

varivel que guarda um ponteiro para o widget perde sua utilidade at o fim do programa, portanto podemos us-la para criar um novo widget. Todo o exemplo anterior pode ser modificado para que os botes de posicionem na vertical. Basta mudar a linha: * caixa = gtk_hbox_new(TRUE, 10); Pela linha: * caixa = gtk_vbox_new(TRUE, 10); Assim criamos um caixa vertical ao invs de horizontal. No entanto, as funes para adicionar os widgets na caixa so as mesmas.

Empacotando com tabelas Uma maneira um pouco mais avanada para empacotar widgets o uso de tabelas. Com este mtodo, criamos uma tabela com um nmero determinado de linhas e colunas, e colocamos os widgets nas clulas formadas. Um detalhe muito interessante que podemos fazer com que um widget ocupe uma ou mais clulas adjacentes. Para criar um nova tabela, usamos a funo: GtkWidget *gtk_table_new( gint rows, gint columns, gint homogeneous ); Onde 'rows' o nmero de linhas, 'columns' o nmero de colunas, e 'homogeneous' um booleano que informa se as clulas tero as mesmas dimenses ou se adaptaro ao widget colocado dentro de si. Em uma tabela, os limites das linhas e colunas so numerados de 0 at o total de linhas ou colunas, como no exemplo a seguir. <tabela.gif> Para adicionar um widget a uma tabela, usamos a funo: void gtk_table_attach ( GtkTable *table, GtkWidget *child, gint left_attach, gint right_attach, gint top_attach, gint bottom_attach, gint xoptions, gint yoptions, gint xpadding, gint ypadding );

O significado dos respectivos parmetros, a seguir: * table - a tabela onde o widget inserido. * child - o widget sendo inserido. * left_attach, right_attach, top_attach, bottom_attach - os limites do widget dentro da tabela, na esquerda, na direita, em cima e em baixo, respectivamente, segundo a figura acima. * xoptions, yoptions - opes sobre a aparncia do widget na horizontal e na vertical: GTK_FILL - o widget se expande para ocupar todo o seu espao na tabela GTK_SHRINK - se a tabela tiver seu tamanho reduzido, o widget ir diminuir para continuar ocupando apenas o seu espao. GTK_EXPAND - as clulas ocupadas pelo widget iro expandir-se para ocupar o espao livre na tabela. * xpadding, ypadding - controla o espao na horizontal e na vertical ao redor dos widgets. Observao: as opes GTK_FILL, GTK_SHRINK e GTK_EXPAND podem ser combinadas fazendo-se o OU bit-a-bit destes valores. Por exemplo: * gtk_table_attach (tabela, widget, 0, 2, 0, 1, (GTK_FILL | GTK_EXPAND), GTK_SHRINK, 0, 0); Realmente a quantidade de parmetros nesta funo a torna um tanto quanto desagradvel e difcil de ser usada. Para isso existe uma funo equivalente a esta com algumas simplificaes: * gtk_table_attach_defaults( GtkTable *table, GtkWidget *widget, gint left_attach, gint right_attach, gint top_attach, gint bottom_attach ); Os parmetros so equivalentes aos da funo gtk_table_attach(), mas repare que esta verso no possui os parmetros xoptions, yoptions, xpadding e ypadding. Esta funo chama a verso original com alguns parmetros padronizados. Os parmetros de opes x e y, so por conveno GTK_FILL | GTK_EXPAND, enquanto o padding x e y so 0. /*** Quarto Exemplo - Tabelas ***/

#include <gtk/gtk.h> void clique(GtkWidget *widget, gpointer data) { g_print("%s foi clicado!\n", (char *)data); } void sair(GtkWidget *widget, gpointer data) { g_print("Saindo...\n"); gtk_main_quit(); } int main(int argc, char **argv) { GtkWidget *janela, *tabela, *boto; gtk_init(&argc, &argv); janela = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_usize(janela, 200, 200); gtk_signal_connect(GTK_OBJECT (janela), "destroy", GTK_SIGNAL_FUNC (sair), NULL); tabela = gtk_table_new(2, 2, TRUE); gtk_container_add(GTK_CONTAINER (janela), tabela); boto = gtk_button_new_with_label("Boto 1"); gtk_signal_connect(GTK_OBJECT (boto), "clicked", GTK_SIGNAL_FUNC (clique), "boto 1"); gtk_table_attach_defaults(GTK_TABLE (tabela), boto, 0, 2, 0, 1); gtk_widget_show(boto); boto = gtk_button_new_with_label("Boto 2"); gtk_signal_connect(GTK_OBJECT (boto), "clicked", GTK_SIGNAL_FUNC (clique), "boto 2"); gtk_table_attach_defaults(GTK_TABLE (tabela), boto, 0, 1, 1, 2); gtk_widget_show(boto); boto = gtk_button_new_with_label("Boto 3"); gtk_signal_connect(GTK_OBJECT (boto), "clicked", GTK_SIGNAL_FUNC (clique), "boto 3"); gtk_table_attach_defaults(GTK_TABLE (tabela), boto, 1, 2, 1, 2); gtk_widget_show(boto); gtk_widget_show(tabela); gtk_widget_show(janela);

gtk_main(); return 0; } /*** Fim do Quarto Exemplo ***/ Vamos comentar as novas linhas de cdigo: * gtk_widget_set_usize(janela, 200, 200); Com esta funo podemos determinar o tamanho da janela manualmente, ou seja, impedir que a janela diminua para se adaptar aos widgets. O primeiro parmetro o widget a ser dimensionado, o segundo a largura, e o terceiro a altura desejada. * tabela = gtk_table_new(2, 2, TRUE); * gtk_container_add(GTK_CONTAINER (janela), tabela); Criamos uma nova tabela, com duas linhas e duas colunas, e clulas do mesmo tamanho. * gtk_table_attach_defaults(GTK_TABLE (tabela), boto, 0, 2, 0, 1); Repare na maneira como adicionamos o boto na tabela, fazendo com que este ocupe mais de uma clula na horizontal (de 0 a 2). No programa adicionamos um total de trs botes fazendo com que um deles ocupem toda a primeira linha e os restantes dividam o espao da segunda linha. Observe a figura a seguir: