criando uma gui linux

24
Iniciando-se no GTK 1. Introdução 1. O que é o GTK/GTK+ 2. O que é um widget 3. Questões práticas 2. Primeiros passos 1. O primeiro programa 2. Como compilar 3. Sinais e "callbacks" 4. Entendendo os widgets 5. Packing Widgets Introdução A interface visual é sem dúvida um dos principais aspectos de um programa. Para determinados usuários, uma interface gráfica pode ser indispensável. Para outros, no mínimo desejável. Por isso, os programadores precisam conhecer uma ferramenta de programação capaz de gerar interfaces amigáveis, como o GTK. Este foi originalmente concebido em C, para ser usado na plataforma Linux, e é muito fácil de ser usado. Para a plena compreensão do conteúdo deste tutorial, supomos que o leitor possua conhecimentos básicos de C. O que é o GTK ? GTK é uma abreviação para GIMP Tool Kit. O GIMP (GNU Image Manipulation Program) é um poderoso editor gráfico, ao estilo do Adobe Photoshop, com licença GPL, o que significa que ele é gratuito, e pode ser

Upload: felipe-lima-morais

Post on 23-Jul-2015

34 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Criando Uma GUI LINUX

Iniciando-se no GTK

1. Introdução 1. O que é o GTK/GTK+ 2. O que é um widget 3. Questões práticas

2. Primeiros passos 1. O primeiro programa 2. Como compilar

3. Sinais e "callbacks" 4. Entendendo os widgets 5. Packing Widgets

Introdução

A interface visual é sem dúvida um dos principais aspectos de um programa. Para determinados usuários, uma interface gráfica pode ser indispensável. Para outros, no mínimo desejável. Por isso, os programadores precisam conhecer uma ferramenta de programação capaz de gerar interfaces amigáveis, como o GTK. Este foi originalmente concebido em C, para ser usado na plataforma Linux, e é muito fácil de ser usado. Para a plena compreensão do conteúdo deste tutorial, supomos que o leitor possua conhecimentos básicos de C.

O que é o GTK ?

GTK é uma abreviação para GIMP Tool Kit. O GIMP (GNU Image Manipulation Program) é um poderoso editor gráfico, ao estilo do Adobe Photoshop, com licença GPL, o que significa que ele é gratuito, e pode ser distribuído livremente. O GTK tem esse nome pois foi originalmente concebido para servir de ferramenta no desenvolvimento do GIMP. Devido a versatilidade das funções do GTK, hoje este é utilizado na produção de diversos outros programas além do GNU Image Manipulation Program, que variam desde pequenos utilitários, 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 funções de outra biblioteca chamada GDK (GIMP Drawing Kit), que por sua vez é um conjunto de funções que chamam

Page 2: Criando Uma GUI LINUX

outras funções de baixo nível do ambiente gráfico em que o programa é compilado. Todo o conjunto do GTK ainda depende de uma biblioteca chamada GLib (GNU Library) de funções úteis, comuns a vários programas GNU, e que aumentam portabilidade.

Existem interfaces de GTK para várias linguagens, embora este documento trate apenas da versão para C. Programar em GTK exige o entendimento de conceitos de orientação a objetos, que não são tão complicados para quem não conhece nada deste estilo de programação, e ainda servem como uma boa introdução 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 aplicação, e é a estrutura fundamental dos programas em GTK. A maioria dos widgets são objetos gráficos como janelas, botões, listas e figuras. Outros são invisíveis, mas permitem controlar coisas como o alinhamento de outros widgets na tela. A grande maioria das funções no GTK serve para manipular os widgets de alguma forma.

Questões práticas

Onde conseguir o GTK. Como instalá-lo e verificar se está funcionando adequadamente ?

A principal e mais confiável fonte para se obter o GTK é com certeza o site do próprio (www.gtk.org) na seção de downloads. De qualquer maneira, o GTK está incluído em todas as principais distribuições 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 versão do GTK instalada no seu sistema. Se não, você deve procurá-lo e instalá-lo.

Page 3: Criando Uma GUI LINUX

Para usuários da RedHat, o GTK esta disponível nos seguintes pacotes RPM:

- gtk+-(versão do pacote).rpm - contém as bibliotecas usadas pelo programa

- gtk+-devel(versão do pacote).rpm - contém os arquivos necessários para desenvolver seus programas com GTK.

O programa gtk-config, que é distribuído junto com o GTK, tem muitas utilidades além de mostrar a sua versão da biblioteca. Digitando apenas gtk-config, você pode ver opções deste comando. Duas dessas opções serão realmente úteis mais adiante quando começarmos a por a mão no código.

Primeiros passos

O primeiro programa

Nesta seção, vamos ver um primeiro exemplo da programação 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 versão para GTK. O código a seguir não faz muito além de mostrar uma janela vazia com o título '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 */

 

Page 4: Criando Uma GUI LINUX

Compilando...

Para compilar o programa acima usando o gcc, podemos usar uma linha de código 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 (atenção, use crases, e não 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 diretórios onde estão cabeçalhos de funções necessários, enquanto a outra mostra a localização das bibliotecas e quais são usadas pelo GTK. Desta maneira você não precisa se preocupar com todos estes pequenos detalhes na hora de compilar o seu programa.

Agora é possível 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 seção 1.4.1.

Entendendo o exemplo...

* #include <gtk/gtk.h>

Isto vai incluir o cabeçalho principal do GTK, que está em um subdiretório chamado gtk no local padrão dos includes (normalmente /usr/include ou /usr/local/include).

* GtkWidget *janela;

Precisamos declarar um ponteiro para um widget que guardará uma referência para o único widget do nosso programa: a janela.

Page 5: Criando Uma GUI LINUX

* gtk_init(&argc, &argv);

Esta função é essencial em todos os programas feitos com GTK e o exemplo não irá rodar sem que ela tenha sido chamada no início da execução. Seu objetivo é preparar variáveis importantes ao GTK e avaliar os argumentos passados na linha de comando para procurar por algumas opções pré-definidas.

* janela = gtk_window_new(GTK_WINDOW_TOPLEVEL);

A função gtk_window_new() cria uma nova janela na memória e retorna um ponteiro para esta janela, para que ela possa ser manipulada por outras funções. O parâmetro passado é o tipo de janela a ser mostrada. Existem três tipos de janela enumeradas no arquivo gtkenums.h. O tipo TOPLEVEL é o mais importante, e é onde a aplicação 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 padrão é o nome do programa compilado, para "Alo Mundo". O primeiro parâmetro é um ponteiro para a janela em questão, e o segundo é uma cadeia de caracteres (string) com o novo titulo. GTK_WINDOW() é uma macro, com o objetivo de fazer a conversão de um ponteiro para um widget, para um ponteiro para janela, pois este é o tipo esperado pela função. O GTK dispõe de várias macros com função de converter entre tipos de variáveis, e estas serão vistas um pouco mais adiante.

* gtk_widget_show(janela);

gtk_widget_show() é uma função que espera como único parâmetro, um ponteiro para um widget, neste caso, a janela, que deve ser mostrado na tela.

* gtk_main();

Com esta função o programa entra em um loop e espera por sinais do usuário como teclas pressionadas no teclado ou movimentos do mouse. É necessário

Page 6: Criando Uma GUI LINUX

avisar ao programa o que fazer quando receber um destes sinais, e este é justamente o próximo assunto.

Observação:

É bem fácil perceber que o GTK possui um número enorme de funções e que nem sempre é possível guardar todos os seus nomes e os parâmetros necessários para cada uma. Uma boa noticia é que os nomes das funções do GTK são muito regulares. Como regra, todas as funções que manipulam um tipo de widget ou objeto do GTK seguem o padrão abaixo:

gtk_{nome do objeto ou widget}_{ação a ser realizada}(parâmetros)

Além disso, muitos widgets compartilham ações entre si. Por exemplo:

gtk_window_new()

gtk_button_new()

gtk_label_new()

Estas funções criam uma janela, um botão, e uma etiqueta, respectivamente, retornando ponteiros para esses widgets.

As macros de conversão de tipo do GTK também seguem um padrão:

GTK_{TIPO} (objeto)

Estas macros checam se o objeto pode ser convertido para o tipo especificado e em seguida fazem a conversão.

Sinais e funções de "callbacks"

Como mencionamos antes, durante o loop gtk_main() os widgets começam a receber sinais que são enviados pelo usuário, e estes podem vir de várias fontes. Para tornar o programa mais interativo, é necessário escrever funções que respondam a estes sinais e acrescentar ao código algo que diga ao programa como relacionar um sinal a aquela função. Isto pode ser feito com a função gtk_signal_connect(), e mostraremos o seu uso no próximo exemplo.

 

Page 7: Criando Uma GUI LINUX

/* 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 modificações feitas no programa.

* void sair(GtkWidget *w, gpointer p);

Page 8: Criando Uma GUI LINUX

Criamos esta função para responder ao sinal de destruição da janela. Este sinal normalmente ocorre quando pressionamos o botão do mouse sobre algum botão na barra de título do programa que fecha a janela. O código desta função simplesmente chama a função do GTK gtk_main_quit(), que sai do loop gtk_main() e continua com o código do programa. No nosso caso, após a chamada de gtk_main() o programa retorna o controle ao sistema operacional.

Precisamos, no entanto, conectar esta função ao sinal de destruição da nossa janela. É então que entra a função gtk_signal_connect(), que recebe 4 parâmetros simples:

gtk_signal_connect(GtkObject *object, gchar *name, GtkSignalFunc func, gpointer func_data);

object - O objeto que recebe o sinal. Como o parâmetro esperado é do tipo GtkObject, a macro GTK_OBJECT é usada, para fazer a conversão 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 vários sinais definidos no GTK para cada tipo de widget. Veremos outros tipos de sinais ao longo do texto.

func - Um ponteiro para a função que vai responder ao sinal em questão. Lembre-se que em C o nome da função é um ponteiro para ela. Esta função deve ter um protótipo do tipo:

void callback_func(GtkWidget *widget, gpointer callback_data);

GTK_SIGNAL_FUNC é uma macro que faz a conversão da função para este padrão.

func_data - Este é um parâmetro passado para a função de callback, cujo propósito depende unicamente do programador.

* botao = gtk_button_new_with_label("Clique aqui");

Esta linha cria um botão com o texto "Clique aqui" sobre ele, que pode responder ao evento de clique do mouse.

Analogamente à janela, conectamos a função clique ao sinal "clicked" no botão. Perceba o uso de uma função g_print() neste callback. Esta função age

Page 9: Criando Uma GUI LINUX

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 botão seja inserido dentro do container (recipiente) janela. Container é uma classe seleta de widgets que podem conter outros widgets, e por isso a macro de conversão é usada.

Observação:

* gtk_widget_show(botao);

* gtk_widget_show(janela);

Perceba a ordem em que os widgets são exibidos. Isso não é meramente por acaso, mas para garantir que quando a janela (que contém todos os outros widgets) apareça, os outros objetos já estejam preparados e sejam mostrados juntos na tela. Assim, evitamos que uma máquina que não seja rápida 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 número enorme de novas funções. Talvez até mais funções do que você esteja normalmente acostumado a usar em seus programas. Entretanto, também é fácil perceber que as funções do GTK são extremamente regulares. Inicialmente, todas as funções do pacote GTK começam com 'gtk_'. Em seguida, o nome da estrutura a ser manipulada ('widget', 'button', 'box', etc), e por último, a ação a ser realizada ('new', 'set_title', 'show', etc). Assim podemos admitir de agora em diante que para criar um novo widget, não importando o seu tipo, basta chamar a função:

* gtk_{tipo de widget}_new ();

Alguns widgets podem ter mais de uma função para criá-los. Um exemplo já conhecido é o botão. Podemos criar um botão vazio com gtk_button_new() ou um que já possua uma etiqueta com gtk_button_new_with_label();

Page 10: Criando Uma GUI LINUX

Outro tipo de funções bem recorrentes são aquelas que lidam com propriedades dos widgets, como gtk_window_set_title() para designar um título a uma janela, ou gtk_widget_set_usize() para redimensionar um widget. Estas funções levam como parâmetro o widget sendo manipulado e os novos atributos (uma string no caso do título, ou dois inteiros no caso das dimensões).

Macros de Conversão de Tipo

Nas chamadas a funções do GTK que recebem widgets como parâmetros, muitas vezes estes devem ser de um tipo específico, como container, ou box, ou window. De uma forma geral, o nome da função já avisa qual será o tipo de parâmetro necessário. Por exemplo, gtk_table_attach() precisa de um parâmetro 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 é possível fazer o casting da variável para o tipo desejado, e se for, fazê-lo.

Os widgets no GTK estão todos em uma hierarquia, como objetos. Existem tipos mais genéricos e outros mais específicos. O tipo GtkObject está no topo da hierarquia, e GtkWidget está logo abaixo. Em orientação à 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 é possível ver um widget como um object com alguns detalhes a mais. Por isso é possível o casting de GtkWidget para GtkObject.

Mais adiante, veremos novos widgets, e entenderemos a sua posição na hierarquia dos widgets.

 

Packing Widgets

Como você deve ter percebido pelo exemplo anterior, quando um widget é colocado em um container (neste caso, o botão posicionado na janela), este geralmente tenta ocupar todo o espaço disponível. 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.

Page 11: Criando Uma GUI LINUX

Existe mais de uma maneira de se empacotar um widget, entretanto elas são bem parecidas, e intuitivas de forma geral. Existem alguns tipos especiais de widget chamados caixas. Um widget caixa é invisível até que algo seja colocado no seu interior. A caixa possui subdivisões 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 função correta. Por exemplo:

* GtkWidget *gtk_hbox_new(gint homogeneous, gint spacing);

A função acima cria uma caixa horizontal com os dois parâmetros passados e retorna um ponteiro para a mesma. O primeiro parâmetro esperado (homogeneous) deve ser do tipo booleano (o GTK possui os valores TRUE e FALSE definidos) e determina se todos as subdivisões da caixa terão o mesmo tamanho. O parâmetro spacing é um inteiro que define o espaçamento em pixels entre um objeto e outro na caixa.

Analogamente existe uma função que cria caixas verticais, e que usa os mesmos parâmetros do exemplo acima:

* GtkWidget *gtk_vbox_new(gint homogeneous, gint spacing);

Após criada, uma caixa pode ser preenchida com vários tipos de widgets (inclusive outras caixas). Isto é feito com as funções 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 parâmetros, mas fazem coisas diferentes ao empacotarem um widget. A primeira função, 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 parâmetro expand é booleano e determina se o espaço 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.

Page 12: Criando Uma GUI LINUX

O parâmetro fill informa se o widget vai ocupar todo o espaço ao seu redor, ou se este vai ficar vazio servindo como espaçamento. Repare que só há espaço em volta do widget se o parâmetro expand for TRUE ou se a caixa foi criada com o parâmetro homogeneous TRUE, logo a opção fill só tem sentido se uma destas condições for satisfeita.

O parâmetro padding é um inteiro que determina o espaço mínimo 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, *botão;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);botão = gtk_button_new_with_label("Botão 1");gtk_signal_connect(GTK_OBJECT (botão), "clicked", GTK_SIGNAL_FUNC (clique), "botão 1");gtk_box_pack_start(GTK_BOX (caixa), botão, FALSE, TRUE, 0);gtk_widget_show(botão);botão = gtk_button_new_with_label("Botão 2");gtk_signal_connect(GTK_OBJECT (botão), "clicked",

Page 13: Criando Uma GUI LINUX

GTK_SIGNAL_FUNC (clique), "botão 2");gtk_box_pack_start(GTK_BOX (caixa), botão, FALSE, TRUE, 0);gtk_widget_show(botão);gtk_widget_show(caixa);gtk_widget_show(janela);gtk_main();return 0;

}

/*** Fim do Terceiro Exemplo ***/

Vamos agora revisar as novas linhas de código:

* 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

* botão = gtk_button_new_with_label("Botão 1");

* gtk_signal_connect(GTK_OBJECT (botão), "clicked", GTK_SIGNAL_FUNC (clique), "botão 1");

* gtk_box_pack_start(GTK_BOX (caixa), botão, FALSE, TRUE, 0);

Criamos um botão com a etiqueta "Botão 1" e adicionamos o sinal de clique do mouse sobre ele. Repare que agora passamos o último parâmetro da função gtk_signal_connect como "botão 1" ao invés de NULL. Este é um dado que está sendo passado para a função de callback clique() como o gpointer "data". Em seguida, adicionamos o botão a caixa com a função gtk_box_pack_start, fazendo com que estes preencham todo o espaço ao seu redor (parâmetro fill igual a TRUE).

Observação: Um detalhe importante deste programa é que usamos um único ponteiro chamado botão para criar dois widgets do tipo botão. Isto é uma técnica muito útil especialmente para economizar variáveis quando seu programa se torna grande. No processo de criação de uma variável widget, escolhemos as suas propriedades, ligamos as funções de callback desejadas, o colocamos em um container, e usamos a função gtk_widget_show() para mostrá-lo na tela. Apenas tenha em mente que após passar por estas etapas, a

Page 14: Criando Uma GUI LINUX

variável 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 botões 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 invés de horizontal. No entanto, as funções para adicionar os widgets na caixa são as mesmas.

Empacotando com tabelas

Uma maneira um pouco mais avançada para empacotar widgets é o uso de tabelas. Com este método, criamos uma tabela com um número determinado de linhas e colunas, e colocamos os widgets nas células formadas. Um detalhe muito interessante é que podemos fazer com que um widget ocupe uma ou mais células adjacentes.

Para criar um nova tabela, usamos a função:

GtkWidget *gtk_table_new( gint rows, gint columns, gint homogeneous );

Onde 'rows' é o número de linhas, 'columns' o número de colunas, e 'homogeneous' é um booleano que informa se as células terão as mesmas dimensões ou se adaptarão ao widget colocado dentro de si.

Em uma tabela, os limites das linhas e colunas são 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 função:

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 );

Page 15: Criando Uma GUI LINUX

O significado dos respectivos parâmetros, 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 - opções sobre a aparência do widget na horizontal e na vertical:

GTK_FILL - o widget se expande para ocupar todo o seu espaço na tabela

GTK_SHRINK - se a tabela tiver seu tamanho reduzido, o widget irá diminuir para continuar ocupando apenas o seu espaço.

GTK_EXPAND - as células ocupadas pelo widget irão expandir-se para ocupar o espaço livre na tabela.

* xpadding, ypadding - controla o espaço na horizontal e na vertical ao redor dos widgets.

Observação: as opções 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 parâmetros nesta função a torna um tanto quanto desagradável e difícil de ser usada. Para isso existe uma função equivalente a esta com algumas simplificações:

* gtk_table_attach_defaults( GtkTable *table, GtkWidget *widget, gint left_attach, gint right_attach,

gint top_attach, gint bottom_attach );

Os parâmetros são equivalentes aos da função gtk_table_attach(), mas repare que esta versão não possui os parâmetros xoptions, yoptions, xpadding e ypadding. Esta função chama a versão original com alguns parâmetros padronizados. Os parâmetros de opções x e y, são por convenção GTK_FILL | GTK_EXPAND, enquanto o padding x e y são 0.

/*** Quarto Exemplo - Tabelas ***/

Page 16: Criando Uma GUI LINUX

#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, *botão;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);botão = gtk_button_new_with_label("Botão 1");gtk_signal_connect(GTK_OBJECT (botão), "clicked", GTK_SIGNAL_FUNC (clique), "botão 1");gtk_table_attach_defaults(GTK_TABLE (tabela), botão, 0, 2, 0, 1);gtk_widget_show(botão);botão = gtk_button_new_with_label("Botão 2");gtk_signal_connect(GTK_OBJECT (botão), "clicked", GTK_SIGNAL_FUNC (clique), "botão 2");gtk_table_attach_defaults(GTK_TABLE (tabela), botão, 0, 1, 1, 2);gtk_widget_show(botão);botão = gtk_button_new_with_label("Botão 3");gtk_signal_connect(GTK_OBJECT (botão), "clicked", GTK_SIGNAL_FUNC (clique), "botão 3");gtk_table_attach_defaults(GTK_TABLE (tabela), botão, 1, 2, 1, 2);gtk_widget_show(botão);gtk_widget_show(tabela);gtk_widget_show(janela);

Page 17: Criando Uma GUI LINUX

gtk_main();return 0;

}

/*** Fim do Quarto Exemplo ***/

Vamos comentar as novas linhas de código:

* gtk_widget_set_usize(janela, 200, 200);

Com esta função podemos determinar o tamanho da janela manualmente, ou seja, impedir que a janela diminua para se adaptar aos widgets. O primeiro parâmetro é 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 células do mesmo tamanho.

* gtk_table_attach_defaults(GTK_TABLE (tabela), botão, 0, 2, 0, 1);

Repare na maneira como adicionamos o botão na tabela, fazendo com que este ocupe mais de uma célula na horizontal (de 0 a 2). No programa adicionamos um total de três botões fazendo com que um deles ocupem toda a primeira linha e os restantes dividam o espaço da segunda linha. Observe a figura a seguir: