33
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 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

Tutorial GTK

  • Upload
    paulo

  • View
    288

  • Download
    4

Embed Size (px)

Citation preview

Page 1: Tutorial GTK

Iniciando-se no GTK1. 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çãoA 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 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

Page 2: Tutorial GTK

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áticasOnde 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.

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

Page 3: Tutorial GTK

return 0;

}/* Fim do Primeiro Exemplo */

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.

* 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

Page 4: Tutorial GTK

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 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.

Page 5: Tutorial GTK

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.

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

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.

Page 6: Tutorial GTK

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 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 WidgetsComo 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

Page 7: Tutorial GTK

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

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 WidgetsComo 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.

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 caixasPara 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

Page 8: Tutorial 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.

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

Page 9: Tutorial GTK

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", 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 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.

Page 10: Tutorial GTK

Empacotando com tabelasUma 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 );

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.

Page 11: Tutorial GTK

/*** 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, *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);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);

Page 12: Tutorial GTK

* 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:

Widgets SelecionadosNeste capítulo iremos apresentar uma visão geral de como usar alguns dos widgets mais comuns fornecidos no pacote do GIMP Toolkit. Procure tirar o máximo proveito dos exemplos, de modo a familiarizar-se com a linguagem.

- Buttons - Range Widgets - Labels - Tooltips

- Dialogs - Text Entries - Combo Box - File Selection

- CList - Tree Widget - Menu Widget - Text Widget

Buttons Como já vimos em nossos exemplos anteriores, podemos criar um botão com as seguintes funções:

* GtkWidget *gtk_button_new(void);

* GtkWidget *gtk_button_new_with_label( gchar *label );

A primeira cria um botão vazio, enquanto a segunda automaticamente insere uma etiqueta de texto no seu interior. Um detalhe interessante é que um botão é considerado um container, portanto é possível inserir outros widgets em seu interior. Um método eficiente é criar uma caixa, inserir todos os widgets desejados nesta e depois inseri-la no botão com gtk_container_add(). Desta maneira é possível criar um botão com um ícone, usando o widget pixmap.

Quanto aos sinais, já vimos que o widget botão suporta "clicked", que ocorre quando um clique do mouse (pressionar e soltar), acontece sobre o botão. Existem ainda os sinais "pressed", quando um botão é pressionado, e "released" quando este é solto. Outros dois sinais, "enter" e "leave", ocorrem respectivamente quando o ponteiro do mouse entra, ou sai de cima do botão.

Page 13: Tutorial GTK

Toggle ButtonUm toggle button funciona como um botão comum exceto pelo fato de que ele conserva o seu estado pressionado. Para criar um novo toggle button, existem as funções:

* GtkWidget *gtk_toggle_button_new(void);

* GtkWidget *gtk_toggle_button_new_with_label( gchar *label );

O toggle button possui um sinal especial chamado "toggled" que é chamado toda vez que o botão é ativado ou desativado. A estrutura do widget possui um campo chamado "active" que diz se este está ativado ou não. Podemos combinar o sinal "toggled" com este campo, para determinar as ações do programa quando o estado do botão muda, como exemplo abaixo.

void toggled_callback( GtkWidget *widget, gpointer data ) {

if( GTK_TOGGLE_BUTTON (widget)->active ) {

/* Botão foi ativado */

} else {

/* Botão foi desativado */

}

}

O estado de um toggle button também pode ser forcado através da função:

* void gtk_toggle_button_set_active( GtkToggleButton *toggle_button, gint state );

Onde toggle_button é o botão em questão e state é um booleano que determina o estado do botão (TRUE = ativado, FALSE = desativado). Sempre que esta função é chamada e o estado do botão é modificado, o sinal "clicked" é emitido pelo widget.

Outra função usada com toggle buttons é:

* void gtk_toggle_button_toggled( GtkToggleButton *toggle_button );

Esta função muda o estado atual de um toggle button.

Check ButtonUm check button funciona como um toggle button, mas é menor e possui o texto à sua direita. Para criar check buttons use as seguintes funções:

* heck_button_new( void );

* gtk_check_button_new_with_label( gchar *label );

O widget check button herda a maioria das funções, campos e sinais dos toggle button, portanto, os métodos citados anteriormente para checar e configurar o estado de um botão, também se aplicam aqui.

Radio ButtonRadio Buttons são usados especialmente em grupo para formar um conjunto de opções ao usuário. Assim como check buttons, esses widgets funcionam como toggle buttons mas, quando agrupados, possuem a característica de serem exclusivos. Isto significa que ao selecionar um radio button,

Page 14: Tutorial GTK

todos os outros do grupo são desativados.

Podemos criar radio buttons com as seguintes funções:

* GtkWidget *gtk_radio_button_new( GSList *group );

* GtkWidget *gtk_radio_button_new_with_label( GSList *group, gchar *label );

O parâmetro group em ambas as funções é um ponteiro para o grupo onde o botão deve ser adicionado. Para o primeiro botão de um grupo este parâmetro deve ser NULL, já que nenhum grupo foi formado ainda. Em seguida podemos chamar a função:

* GSList *gtk_radio_button_group( GtkRadioButton *radio_button );

Para criar um novo grupo contendo o radio button passado como parâmetro. O grupo retornado por esta função pode ser passado como parâmetro na criação de novos radio buttons.

Em geral é desejado designar um botão para aparecer selecionado por padrão, quando o programa é iniciado. Para isso usamos a mesma função que ativa toggle buttons já vista neste texto, gtk_toggle_button_set_active(). Uma vez que o radio button herda propriedades do toggle button, não há problema em fazer o casting com a macro GTK_TOGGLE_BUTTON().

Veja o exemplo demonstrando as principais características dos 4 tipos de botões discutidos nesta seção. A partir de agora, você já possui experiência suficiente com o código para precisar de comentários para cada linha.

Range WidgetsAs barras de rolagem (scrollbars widgets) e os widgets de escala (scale widgets) compõem o grupo dos range widgets. Os range widgets, do inglês widgets de extensão, são formados por uma barra ("trough") dentro da qual o usuário pode movimentar um botão ("slider"). Observe:

Os scrollbars permitem ao usuário navegar por um texto, por uma lista de valores ou qualquer outro tipo de informação disposta numa janela. Já os scale widgets são usados para selecionar e manipular um valor numa faixa específica. Para todos os fins, a única diferença entre os scale widgets e os scrollbar widgets é que os primeiros permitem ao usuário visualizar, ao lado da barra, o valor corrente assumido pelo controle. Veja as figuras a seguir, e compare um scale widget (acima) com um scrollbar:

Pelo fato de funcionarem de forma quase idêntica, iremos tratar aqui apenas dos scrollbars widgets. Para entendermos como funciona um scrollbar, é necessário antes compreender como funciona a interação entre os range widgets e os widgets aos quais estes estão associados. Tomemos como exemplo um widget do tipo caixa de texto (text widget) associado uma barra de rolagem vertical (vertical scrollbar). Observe:

Page 15: Tutorial GTK

Gostaríamos que quando o usuário manipulasse a scrollbar, deslizando o "slider", o texto exibido na caixa refletisse essa operação, rolando para cima ou para baixo. Por outro lado, quando o usuário adicionasse texto à caixa, gostaríamos que o visual da barra de rolagem (scrollbar) se modelasse de acordo com o novo conteúdo. Tudo isso pode ser feito de forma semi automática usando-se os objetos do tipo ajuste (adjustments). Os adjustments guardam informações que podem ser compartilhadas pelos objetos a ele associados.

Para criar um novo adjustment, use a função:

GtkObject *gtk_adjustment_new ( gfloat value, gfloat lower, gfloat upper, gfloat step_increment, gfloat page_increment, gfloat page_size);

onde value é o valor assumido pelo controle. Lower é o valor mínimo que o ajuste pode assumir, associado a posição mais a esquerda (no caso de barras de rolagem horizontais) ou superior (barras de rolagem verticais) da barra. Upper é a coordenada associada a posição mais a direita ou inferior da barra. Step_increment indica o menor dos dois incrementos através dos quais o usuário pode alterar value, o que ocorre quando o usuário clicar sobre uma das setas na scrollbar, por exemplo. Já page_increment indica o maior. Page_size indica o tamanho do "slider". Uma observação interessante é que o campo upper não especifica o valor máximo que o adjustment pode assumir, mas sim a coordenada associada a posição mais a direita (barras horizontais) ou inferior (barras verticais). Observe com cuidado o primero dos três exemplos abaixo, no qual o valor máximo que o adjustment pode assumir é 80, e não 100, como poderíamos imaginar.

Para criar uma nova barra de rolagem use uma das seguintes funções:

GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );

GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );

Eis a seguir alguns exemplos:

Page 16: Tutorial GTK

Na prática, entretanto, você raramente precisará criar os adjustments usando a função acima apresentada. No nosso caso particular do text widget associado à scrollbar, podemos deixar esta tarefa a cargo da função de geração da caixa texto (consulte a explicação sobre o text widget para mais detalhes):

/* a caixa texto cria seus próprios ajustes */

text = gtk_text_new ( NULL, NULL )

/* use o recém criado ajuste para controlar a scrollbar */

vscrollbar = gtk_vscrollbar_new ( GTK_TEXT(text) -> vadj );

A interação entre a scrollbar e a caixa texto dá-se através dos ajustes (adjustments). A caixa texto apenas consulta o campo "value" da estrutura "adjustment", a fim de exibir a porção adequada do texto na janela. Para determinados procedimentos do usuário, como inserir mais texto na caixa, esta última altera os outros campos do "adjustment". Já a barra de rolagem vertical altera apenas o valor do campo "value", quando o usuário movimento o "slider", consultando todos os outros campos a fim de modelar a sua forma. Observe:

LabelsUm label é uma etiqueta com um texto associado a ela. É usada amplamente no layout de um programa para dar explicações sobre os campos de um formulário. Labels não possuem sinais, portanto, para capturar eventos é necessário inseri-la em outros widgets. Existe apenas uma função para criar labels:

* GtkWidget *gtk_label_new( const gchar *str );

Onde str é o texto contido na etiqueta. É possível mudar este texto durante o código do programa, isto é, após a criação da label, com a função:

* void gtk_label_set_text( GtkLabel *label, const gchar *str );

O argumento label é o widget a ser modificado e str é o novo conteúdo da etiqueta.

Para ler o texto de uma label, pode ser usada a função:

* void gtk_label_get( GtkLabel *label, gchar **str );

Page 17: Tutorial GTK

O parâmetro str é um ponteiro para uma string e é onde o texto da etiqueta será retornado. Repare que pelo retorno ser um ponteiro para a variável que guarda a string na etiqueta, não é aconselhável manipular este valor.

É possível configurar o alinhamento do texto na etiqueta com a seguinte função:

* void gtk_label_set_justify( GtkLabel *label, GtkJustification jtype );

O parâmetro jtype é o tipo de justificação desejado, e GtkJustification é uma enumeração definida em gtkenums.h. Os valores possíveis são:

GTK_JUSTIFY_LEFTGTK_JUSTIFY_RIGHTGTK_JUSTIFY_CENTERGTK_JUSTIFY_FILL

Se nada for especificado, o texto de um label fica centralizado por padrão. Para usar quebra de linha quando o texto fica maior que a etiqueta, use a função:

* void gtk_label_set_line_wrap( GtkLabel *label, gboolean wrap );

Onde wrap pode ser TRUE (ativa o retorno de linha) ou FALSE (desativa o retorno de linha).

Para sublinhar o texto de um label o GTK usa o esquema de strings de padrões. Uma string deste tipo pode conter caracteres '_' (underscore) ou ' ' (espaço em branco). O padrão é sobreposto ao texto na etiqueta, e os caracteres sob os símbolos de underscore são sublinhados. A função usada para definir o padrão de um label é:

* void gtk_label_set_pattern( GtkLabel *label, const gchar *pattern );

Portanto, para criar um label com o texto "Aviso Importante!" e sublinhar a palavra importante, faríamos o seguinte:

etiqueta = gtk_label_new( "Aviso Importante!" );

gtk_label_set_pattern( etiqueta, " __________" );

Consulte o exemplo para familiarizar-se com o label widget.

TooltipsUma tooltip é uma pequena etiqueta de texto que aparece sobre um widget, quando o ponteiro do mouse fica parado por algum tempo sobre ele. Estes são widgets muito simples e de rápida implementação. Para criar um tooltip widget, use a função:

* GtkTooltips *gtk_tooltips_new( void );

Após criar um tooltip é necessário associá-lo ao widget a que ele se refere, e determinar o texto a ser exibido.

* void gtk_tooltips_set_tip( GtkTooltips *tooltips, GtkWidget *widget, const gchar *tip_text, const gchar *tip_private );

O primeiro e segundo parâmetros são respectivamente o tooltip criado e o widget que vai ser associado a ele. O parâmetro tip_text é o texto a ser exibido pelo tooltip, enquanto 'tip_private' esta' relacionado a outro tipo de widget - GtkTipsQuery - e pode ser dispensado passando NULL em seu lugar.

Para ativar ou desativar um tooltip existem duas funções simples:

* void gtk_tooltips_enable( GtkTooltips *tooltips );

Page 18: Tutorial GTK

* void gtk_tooltips_disable( GtkTooltips *tooltips );

Outras funções para configurar o funcionamento de um tooltip:

* void gtk_tooltips_set_delay( GtkTooltips *tooltips, gint delay);

* void gtk_tooltips_set_colors( GtkTooltips *tooltips, GdkColor *background, GdkColor *foreground );

A primeira determina o tempo em milissegundos entre o evento de entrada do mouse no widget e o aparecimento do tooltip. O padrão para este valor é 500. A outra função configura as cores de fundo e do texto, respectivamente passadas como os parâmetros background e foreground.

Recomendamos agora que você faça download do exemplo e examine-o com atenção.

DialogsDialogs são simples janelas com o objetivo de passar alguma mensagem importante ao usuário. Elas normalmente aparecem avisando que alguma coisa deu errado ou para pedir confirmação de alguma ação do usuário. Para criar um dialog, use a função:

* GtkWidget *gtk_dialog_new( void );

No código do GTK, um dialog não passa de um widget window com uma caixa vertical dividida em duas partes por um separador horizontal. A área superior serve para empacotar a mensagem a que se refere o dialog. A parte de baixo da janela contém uma outra caixa, desta vez horizontal, chamada 'action_area', onde podem ser colocados um ou mais botões que representam as possíveis opções do usuário.

No arquivo gtkdialog.h a estrutura GtkDialog esta descrita da seguinte maneira:

struct GtkDialog {

GtkWindow window;GtkWidget *vbox;GtkWidget *action_area;

};

O campo window é a janela de dialogo em si, enquanto vbox e action_area são as caixas vertical e horizontal já mencionadas. Para adicionar widgets as caixas de dialogo usamos as mesmas funções para caixas. Podemos adicionar textos facilmente a parte superior da janela:

dialogo = gtk_dialog_new();texto = gtk_label_new( "Tem certeza que quer sair do programa?" );gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialogo )->vbox ), texto, TRUE, TRUE, 0 );gtk_widget_show(texto);

Da mesma maneira, acrescentamos os botões a caixa horizontal:

botao = gtk_button_new_with_label("Sim");gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialogo )->action_area ), botao, TRUE, TRUE, 0 );gtk_widget_show(botao);botao = gtk_button_new_with_label("Não");gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialogo )->action_area ), botao, TRUE, TRUE, 0 );gtk_widget_show(botao);

Page 19: Tutorial GTK

Note como, em ambos os casos, fizemos o casting da variável 'dialogo' para GtkDialog antes de poder acessar os campos 'vbox' e 'action_area'. Lembre-se que o tipo GtkWidget (como a variável 'dialogo' foi declarada) não possui estes campos. Outro detalhe importante é que os botões adicionados ao dialog ainda precisam de funções de callback para realizar alguma ação, quando clicados.

Também é possível fazer construções mais complicadas com caixas de dialogo, adicionando outros tipos de widgets de empacotamento nas áreas da janela, como outras caixas ou mesmo tabelas.

Text entriesEstes widgets são pequenas caixas de texto de apenas uma linha, para ler entrada no teclado do usuário. Eles podem ser criador com duas funções:

* GtkWidget *gtk_entry_new( void );

* GtkWidget *gtk_entry_new_with_max_length( guint16 max );

A segunda função permite criar uma caixa de texto com um numero máximo de caracteres, passado no parâmetro max.

O conteúdo de uma destas caixas de texto pode ser lido com a função:

* gchar *gtk_entry_get_text( GtkEntry *entry );

Para modificar o texto em uma entry, existem três funções:

* void gtk_entry_set_text( GtkEntry *entry, const gchar *text );

* void gtk_entry_append_text( GtkEntry *entry, const gchar *text );

* void gtk_entry_prepend_text( GtkEntry *entry, const gchar *text );

A primeira função simplesmente altera o conteúdo da caixa de texto para a string no parâmetro text. A segunda e terceira funções inserem texto no final e no inicio da caixa respectivamente, sem remover o conteúdo anterior.

A posição do cursor em uma caixa de texto também pode ser configurada com a seguinte função:

* void gtk_entry_set_position( GtkEntry *entry, gint position );

Uma text entry também pode ficar desabilitada por algum tempo, para impedir que o usuário modifique o seu conteúdo enquanto isto não é desejado. Para isto use:

* void gtk_entry_set_editable( GtkEntry *entry, gboolean editable );

O segundo parâmetro indica se a text entry pode ser editada (editable = TRUE), ou não (editable = FALSE).

Em algumas situações também é útil esconder o texto que está sendo digitado, como no caso de uma senha.

* void gtk_entry_set_visibility( GtkEntry *entry, gboolean visible );

Onde visible pode ser TRUE (texto visível), ou FALSE (texto escondido).

Para fazer seleções no texto contido na text entry, use a função:

* void gtk_entry_select_region( GtkEntry *entry, gint start, gint end );

O parâmetro 'start' é o primeiro caractere da seleção enquanto 'end' é o ultimo.

O widget entry possui dois sinais muito úteis para saber quando o texto foi modificado: "changed" e

Page 20: Tutorial GTK

"activate". O primeiro ocorre quando o conteúdo da caixa é modificado por qualquer motivo, enquanto "activate" acontece apenas quando a tecla ENTER é pressionada no texto.

Combo Box A Combo Box consiste-se de uma caixa de entrada de texto e de um menu a partir do qual o usuário pode selecionar uma dentre diversas alternativas predefinidas. É possível ainda digitar na caixa de texto qualquer conteúdo, diretamente.

Note que a Combo Box, do inglês Combination Box, tem esse nome pois é, na realidade, uma combinação de outros widgets. Mais precisamente, uma Combo Box é formada por uma entrada de texto, um botão, um menu do tipo "pop up" e uma lista com as alternativas predefinidas, além de outros widgets secundários. Veja a seguir parte da estrutura que define uma Combo Box:

struct _GtkCombo {

GtkHBox hbox;GtkWidget *entry;GtkWidget *button;GtkWidget *popup;GtkWidget *popwin;GtkWidget *list;...

}

Entry e list são os widgets que por hora interessam-nos.

Criando uma Combo BoxPara criar uma Combo Box, use a função:

GtkWidget *gtk_combo_new( void );

Definindo valoresPara definir o valor padrão exibido na caixa texto deve-se manipular o campo entry:

gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "Valor padrão");

Para definir os campos a serem incluídos na lista "pop down" use a função:

Page 21: Tutorial GTK

void gtk_combo_set_popdown_string( GtkCombo *combo, GList *strings );

Note que é necessário passar como parâmetro para esta função uma lista (que nesse caso será do tipo encadeada) com as strings de alternativas predefinidas. É muito simples definir essa lista. Basta seguir o seguinte modelo:

GList *glist = NULL;

glist = g_list_append(glist, "String 1");

glist = g_list_append(glist, "String 2");

glist = g_list_append(glist, "String 3");

glist = g_list_append(glist, "String 4");

gtk_combo_set_popdown_string( GTK_COMBO(combo), glist);

É bom ressaltar que após chamar esta função, pode-se liberar a memória que está sendo ocupada pelo ponteiro previamente declarado, usando algo como:

g_list_free (glist);

Trabalhando com a Combo BoxPara ler o conteúdo da entrada de texto de uma Combo Box basta chamar a função:

gchar *gtk_entry_get_text(GtkEntry *entry);

onde o parâmetro será do tipo GTK_ENTRY(GTK_COMBO(combo )->entry).

Para associar uma função ao sinal ativado quando o usuário pressionar a tecla Enter, use algo como:

gtk_signal_connect ( GTK_OBJECT(combo)->entry), "activate", GTK_SIGNAL_FUNC(callback_function), data);

Clique aqui para fazer o download do exemplo.

File SelectionO widget de seleção de arquivos permite que se crie facilmente janelas com caixas de diálogo para acessar arquivo. A janela vem completa, inclusive com os botões Ok, Cancel e Help.

Page 22: Tutorial GTK

Criando um widget File SelectoinPara criar uma nova caixa de seleção de arquivos use a função:

GtkWidget *gtk_file_selection_new( gchar *title );

Manipulando uma File SelectionA seguinte função serve para definir o diretório ou o arquivo padrão:

void gtk_file_selection_set_filename ( GtkFileSelection *filesel, gchar *filename);

Para acessar o texto com o caminho/arquivo selecionados pelo usuário, utilize:

gchar * gtk_file_selection_get_filename( GtkFileSelection *filesel);

Alguns ponteiros contidos no widget de seleção de arquivos são:

dir _listfile_listselection_entryselection_textmain_vboxok_buttoncancel_buttonhelp_button

Para conectar o botão Ok à função file_ok_sel, por exemplo, use:

gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),"clicked",

Page 23: Tutorial GTK

(GtkSignalFunc) file_ok_sel, fs);

Clique aqui para fazer o download do exemplo.

CList (Columned List)O widget CList é uma lista com várias colunas capaz de comportar inúmeras linhas de informação. Cada coluna, por sua vez, poderá ter um título.

Criando uma CListPara criar uma CList, use uma das duas seguintes funções:

GtkWidget *gtk_clist_new ( gint columns );

GtkWidget *gtk_clist_new_with_titles ( gint columns, gchar *titles[] );

A primeira forma cria uma lista com um determinado número de colunas, sem títulos, enquanto que a segunda cria uma lista com títulos, passados através do parâmetro titles.

Modos de operaçãoPode-se permitir que o usuário selecione apenas uma linha da lista de cada vez, ou que este possa selecionar várias linhas ao mesmo tempo, o que é definido através da função:

void gtk_clist_set_selection_mode ( GtkCList *clist, GtkSelectionMode mode );

Entre os modos de operação podemos citar:

- GTK_SELECTION_SINGLE - admite a seleção de um ou nenhum item por parte do usuário. A seleção será sempre ou do tipo NULL, caso nada esteja selecionado, ou um ponteiro de uma GList apontando para um único item selecionado.

- GTK_SELECTION_BROWSE - admite um item selecionado. Quando criada, a CList não possuirá nenhum item selecionado (a seleção será do tipo NULL). Entretanto, a partir do momento em que o usuário selecione um item, este terá sempre um, e exatamente um, item selecionado.

- GTK_SELECTION_MULTIPLE - admite seleção de múltiplos items. A seleção será NULL ou um ponteiro de uma GList apontando para o primeiro item selecionado, que por sua vez apontará para o segundo item selecionado, e assim por diante (os itens selecionados ficam armazenados numa lista encadeada).

Page 24: Tutorial GTK

- GTK_SELECTION_EXTENDED - não admite a seleção de itens. O usuário não poderá selecionar nenhum item, e a seleção será sempre do tipo NULL.

Outra função interessante é a que define a borda da CList:

void gtk_clist_set_shadow_type( GtkCList *clist, GtkShadowType border );

Onde alguns dos possíveis valores do tipo de borda são:

GTK_SHADOW_NONEGTK_SHADOW_INGTK_SHADOW_OUT

Manipulando uma CListPara definir o tamanho da largura das colunas, e a altura das linhas, use respectivamente as seguintes funções:

void gtk_clist_set_column_width( GtkCList *clist, gint column, gint width );

void gtk_clist_set_row_height( GtkCList *clist, gint height );

Adicionando linhasPara adicionar uma linha à lista use uma das seguintes funções:

gint gtk_clist_prepend( GtkCList *clist, gchar *text[] );

gint gtk_clist_append( GtkCList *clist, gchar *text[] );

void gtk_clist_insert( GtkCList *clist, gint row, gchar *text[] );

O valor retornado pelas duas primeiras funções indica a linha na qual o texto foi adicionado. A quantidade de strings armazenadas no ponteiro text deve ser igual ao número de colunas na CList. Se o argumento text[] for nulo, será criada uma linha em branco.

Para obter o conteúdo de uma célula, use:

gint gtk_clist_get_text ( GtkCList *clist, gint row, gint column, gchar **text );

O valor retornado em text será o texto contido na coluna e linha solicitadas.

Lidando com seleçõesQuando o usuário clicar sobre uma determinada célula da tabela, pode-se identificar a linha selecionada e a coluna da célula apontada. Para tanto, basta usar um dos seguintes sinais:

- select_row - este sinal retorna as seguintes informações, nesta ordem: GtkClist *clist, gint row, gint column, GtkEventButton *event

- unselect_row - este sinal é emitido quando o usuário desmarca uma linha, e retorna as mesma informações que o sinal anterior

- click_column - retorna, nesta ordem: GtkClist *clist, gint column.

Para associar uma função de callback ao sinal select_row, por exemplo, esta deve ser declarada como:

void select_row_callback ( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data);

E a função deve ser conectada à lista CList usando:

gtk_signal_connect(GTK_OBJECT( clist ) , "select_row", GTK_SIGNAL_FUNC

Page 25: Tutorial GTK

( select_row_callback ), NULL);

Clique aqui para fazer o download do exemplo.

Tree Widget O objetivo do widget do tipo árvore é exibir informações organizadas hierarquicamente. O widget do tipo Tree (árvore) é na realidade um container para widgets do tipo TreeItem.

Observações iniciaisÉ importante entender alguns detalhes sobre o seguinte esquema. Os comentários aqui descritos sobre árvores seguem a nomenclatura usada pelo GTK, que pode ser um pouco distinta da usual na ciência da computação.

A árvore 1 possui dois itens, A e B. Sob o item A foi adicionada uma árvore 2, que por sua vez possui três itens, C, D e E. Atenção! Os itens C, D e E possuem um pai em comum, que é a árvore 1. Ou seja, tecnicamente, no GTK, o pai de uma sub-árvore é uma árvore. Além disso, a árvore 1 é a

Page 26: Tutorial GTK

árvore raiz (root tree) pois ela engloba todos os itens apresentados. Finalmente, é bom frisar que toda sub-árvore é uma árvore.

Criando uma árvorePara criar uma árvore, use:

GtkWidget *gtk_tree_new ( void );

Em geral, é interessante empacotar os widgets do tipo Tree dentro de uma janela de rolagem (ScrolledWindow). Consulte o exemplo para mais detalhes.

Para adicionar itens à árvore, basta usar a seguinte função

GtkWidget *gtk_tree_item_new_with_label( gchar *label );

seguida por uma das duas seguintes funções

void gtk_tree_append( GtkTree *tree, GtkWidget *tree_item );

void gtk_tree_prepend( GtkTree *tree, GtkWidget *tree_item );

Adicionando sub-árvoresPara adicionar uma sub-árvore sob um item de uma árvore utilize a função

void gtk_tree_item_set_subtree ( GtkTreeItem *tree_item, GtkWidget *subtree );

onde tree_item é o item sob o qual será adicionada a nova sub-árvore.

Atenção! O tree_item em questão deverá ter sido adicionado a uma árvore antes de se chamar a função acima. Isto deve ser feito pois o pai da nova sub-árvore será esta árvore que guarda o tree_item.

A lista de seleçõesO widget do tipo árvore permite que selecione-se itens nele contidos . É a árvore raiz (root tree) que guarda a lista de todos os itens que estão selecionados em qualquer uma de suas sub-árvores. Quando um item de uma árvore é selecionado, este aciona o evento "select" enquanto que a árvore que o contém emite o sinal "select_child". A árvore raiz, por sua vez, irá emitir o sinal de "selection_changed" sempre que qualquer item desta ou de uma de suas sub-árvores for marcado ou desmarcado.

Clique aqui para fazer o download do exemplo.

Menu WidgetO menu widget permite que se crie menus personalizados para suas aplicações de maneira bem simples. No GTK existem basicamente dois tipos de menu: menus de barra (menu bar) e menus de opções (options menu). Iremos tratar aqui dos menus do primeiro tipo.

Page 27: Tutorial GTK

Existem duas formas de criar-se menus no GTK. Uma mais complicada, que permite inclusive colocar imagens nas opções apresentadas, e outra mais simples, porém um pouco mais limitada, a qual iremos aqui abordar. Inicialmente, é interssante entender a nomenclatura utilizada:

O processo basicamente divide-se em duas etapas. Primeiro deve-se definir a estrutura que delineará o menu, e em seguida este deverá ser ativado.

A estrutura usada para gerar os itens do menu é a GtkItemFactoryEntry, que compõem-se pelos cinco itens a seguir:

item 1: a etiqueta do item do menu. Letras precedidas por um '_' serão consideradas como teclas de atalho apenas quando o menu for aberto.

item 2: tecla de atalho para a entrada. Este item não será abordado neste tutorial (iremos passar o valor NULL como parâmetro).

item 3: função de callback a ser chamada quando o usuário selecionar determinada opção.

item 4: o tipo do item. Alguns dos possíveis valores são:

NULL ou "" ou "<Item>", item simples"<Title>", item de título"<CheckItem>""<ToggleItem>""<RadioItem>""<Separator>", separador"<Branch>", cria um item que guarda sub itens"<LastBranch>", alinha o item a direita

Uma vez definido o menu, determinadas funções deverão ser chamadas para que o mesmo seja efetivamente criado. Observe o exemplo.

Text WidgetO widget de texto permite que múltiplas linhas de texto sejas mostradas e editadas na tela.

Page 28: Tutorial GTK

Criando um text widgetPara criar um widget de caixa texto, use:

GtkWidget *gtk_text_new ( GtkAdjustment *hadj, GtkAdjustment *vadj );

Passar o valor NULL para os parâmetros fará com que a função crie seus próprios ajustes.

O widget de texto não cria automaticamente a barra de rolagem vertical. Para criá-la, deve-se fazer algo como:

vscrollbar = gtk_vscrollbar_new ( GTK_TEXT(text) -> vadj );

gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);

gtk_widget_show( vscrollbar );

A barra de rolagem horizontal não é suportada pelo widget de texto. É possível, entretanto, quebrar as linhas longas usando a função:

void gtk_text_set_word_wrap ( GtkText *text, gint word_wrap );

onde word_wrap assume valor TRUE ou FALSE.

Propriedades do text widgetO widget de texto pode ser usado tanto para apenas exibir textos quanto para permitir que o usuário entre ou altere informações. Para definir o modo de operação do widget, use a função:

void gtk_text_set_editable ( GtkText *text, gint editable );

onde editable pode ser TRUE ou FALSE.

Finalmente, para saber o tamanho do texto contido numa caixa de texto use

guint gtk_text_get_length( GtkText *text );

e para obter o conteúdo de uma caixa texto

gchar *gtk_editable_get_chars( GtkEditable *editable, gint start_pos, gint end_pos );

Exemplo:

/**************************************************

*

* Exemplo de uso do text widget.

*

**************************************************/

#include <stdio.h>

#include <gtk/gtk.h>

void text_toggle_editable (GtkWidget *checkbutton,

Page 29: Tutorial GTK

GtkWidget *text)

{

gtk_text_set_editable(GTK_TEXT(text),

GTK_TOGGLE_BUTTON(checkbutton)->active);

}

void text_toggle_word_wrap (GtkWidget *checkbutton,

GtkWidget *text)

{

gtk_text_set_word_wrap(GTK_TEXT(text),

GTK_TOGGLE_BUTTON(checkbutton)->active);

}

void close_application( GtkWidget *widget, gpointer data )

{

gtk_main_quit();

}

int main (int argc, char *argv[])

{

GtkWidget *window;

GtkWidget *box1, *hbox, *check;

GtkWidget *table;

GtkWidget *vscrollbar;

GtkWidget *text;

GdkColormap *cmap;

GdkColor colour;

GdkFont *fixed_font;

FILE *infile;

gtk_init (&argc, &argv);

Page 30: Tutorial GTK

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

gtk_widget_set_usize (window, 600, 500);

gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);

gtk_signal_connect (GTK_OBJECT (window), "destroy",

GTK_SIGNAL_FUNC(close_application),

NULL);

gtk_window_set_title (GTK_WINDOW (window), "Exemplo Text Widget");

gtk_container_set_border_width (GTK_CONTAINER (window), 0);

box1 = gtk_vbox_new (FALSE, 0);

gtk_container_add (GTK_CONTAINER (window), box1);

gtk_widget_show (box1);

table = gtk_table_new (1, 1, FALSE);

gtk_box_pack_start (GTK_BOX (box1), table, TRUE, TRUE, 0);

gtk_widget_show (table);

/* Cria um widget do tipo texto */

text = gtk_text_new (NULL, NULL);

gtk_text_set_editable (GTK_TEXT (text), TRUE);

gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,

GTK_EXPAND | GTK_SHRINK | GTK_FILL,

GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);

gtk_widget_show (text);

/* Adicona-se uma barra vertical ao widget */

vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);

gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,

GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);

gtk_widget_show (vscrollbar);

Page 31: Tutorial GTK

/* Pega-se o mapa de cores do sistema, e aloca-se a cor vermelha */

cmap = gdk_colormap_get_system();

colour.red = 0xffff;

colour.green = 0;

colour.blue = 0;

if (!gdk_color_alloc(cmap, &colour)) {

g_error("Nao foi possivel alocar a cor!");

}

/* Carrega-se uma fonte fixa */

fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");

/* A chamada aa funcao a seguir cria uma janela para o text widget

pronta para inserirmos o texto */

gtk_widget_realize (text);

/* Congela-se o text widget, de modo que possamos fazer atualizacoes

no mesmo */

gtk_text_freeze (GTK_TEXT (text));

/* Exibe-se uma mensagem com diferentes cores e fontes */

gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,

"O text widget suporta ", -1);

gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,

"cores ", -1);

gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,

"e diferentes fontes!\n\n", -1);

/* Carrega-se o arquivo text.c na janela texto */

infile = fopen("text.c", "r");

Page 32: Tutorial GTK

if (infile) {

char buffer[1024];

int nchars;

while (1)

{

nchars = fread(buffer, 1, 1024, infile);

gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,

NULL, buffer, nchars);

if (nchars < 1024)

break;

}

fclose (infile);

}

/* Descongela o text widget, de modo que as modificacoes tornem-se visiveis */

gtk_text_thaw (GTK_TEXT (text));

hbox = gtk_hbutton_box_new ();

gtk_box_pack_start (GTK_BOX (box1), hbox, FALSE, FALSE, 0);

gtk_widget_show (hbox);

check = gtk_check_button_new_with_label("Editavel");

gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);

gtk_signal_connect (GTK_OBJECT(check), "toggled",

GTK_SIGNAL_FUNC(text_toggle_editable), text);

gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);

gtk_widget_show (check);

Page 33: Tutorial GTK

check = gtk_check_button_new_with_label("Quebra linhas (Wrap Words)");

gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);

gtk_signal_connect (GTK_OBJECT(check), "toggled",

GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);

gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);

gtk_widget_show (check);

gtk_widget_show (window);

gtk_main ();

return(0);

}