0% acharam este documento útil (0 voto)
29 visualizações33 páginas

Introdução ao GTK para Iniciantes

Este documento fornece uma introdução ao GTK e widgets, discutindo: 1) O que é o GTK e widgets; 2) Como criar um primeiro programa "Olá Mundo" em GTK; 3) Como adicionar sinais e callbacks para interatividade.

Enviado por

paulo
Direitos autorais
© Attribution Non-Commercial (BY-NC)
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
29 visualizações33 páginas

Introdução ao GTK para Iniciantes

Este documento fornece uma introdução ao GTK e widgets, discutindo: 1) O que é o GTK e widgets; 2) Como criar um primeiro programa "Olá Mundo" em GTK; 3) Como adicionar sinais e callbacks para interatividade.

Enviado por

paulo
Direitos autorais
© Attribution Non-Commercial (BY-NC)
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

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:
- [Link]
- [Link]
- [Link]
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
([Link]) 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 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 */

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
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.
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.
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 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();
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.
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.
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", 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.
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.
<[Link]>
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.
/*** 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);
* 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 Selecionados
Neste 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.
Toggle Button
Um 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 Button
Um 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 Button
Radio 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,
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 Widgets
As 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:
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:
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:

Labels
Um 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 );
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_LEFT
GTK_JUSTIFY_RIGHT
GTK_JUSTIFY_CENTER
GTK_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.

Tooltips
Uma 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 );
* 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.

Dialogs
Dialogs 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);
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 entries
Estes 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
"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 Box


Para criar uma Combo Box, use a função:
GtkWidget *gtk_combo_new( void );

Definindo valores
Para 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:
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 Box


Para 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 Selection
O 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.
Criando um widget File Selectoin
Para criar uma nova caixa de seleção de arquivos use a função:
GtkWidget *gtk_file_selection_new( gchar *title );

Manipulando uma File Selection


A 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 _list
file_list
selection_entry
selection_text
main_vbox
ok_button
cancel_button
help_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",
(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 CList


Para 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ção
Pode-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).
- 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_NONE
GTK_SHADOW_IN
GTK_SHADOW_OUT
Manipulando uma CList
Para 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 linhas
Para 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ções


Quando 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
( 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
árvore raiz (root tree) pois ela engloba todos os itens apresentados. Finalmente, é bom frisar que
toda sub-árvore é uma árvore.

Criando uma árvore


Para 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-árvores
Para 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ções
O 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 Widget
O 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.
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 Widget
O widget de texto permite que múltiplas linhas de texto sejas mostradas e editadas na tela.
Criando um text widget
Para 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 widget


O 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,


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


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);
/* Pega-se o mapa de cores do sistema, e aloca-se a cor vermelha */

cmap = gdk_colormap_get_system();

[Link] = 0xffff;

[Link] = 0;

[Link] = 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");


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

Você também pode gostar