GTK+/Avançando
Capítulo 4: Avançando
Tipos de dados
[editar | editar código-fonte]Algumas coisas que você deve ter percebido nos exemplos anteriores precisam ser explicadas agora. Os tipos gint, gchar, etc. que você vê são typedefs para os tipos int e char, respectivamente, e fazem parte do sistema da GLib. Isso é necessário para contornar a horrível dependência no tamanho de tipos simples de dados, que aparece por causa de cálculos que precisam ser feitos.
Um bom exemplo é o tipo "gint32" que corresponderá sempre a um inteiro de 32 bits, para qualquer plataforma ― seja o alpha de 64 bits ou o i386 de 32 bits. Essas definições são bastante diretas e intuitivas. O código de todas elas está em glib/glib.h (arquivo incluído por gtk.h).
Você também notará a habilidade do GTK de usar o tipo GtkWidget quando a função pede um GtkObject. O GTK foi feito de maneira orientada a objetos, e um widget é um objeto.
Mais sobre tratadores de sinal
[editar | editar código-fonte]Vamos dar mais uma olhada na declaração de g_signal_connect().
gulong g_signal_connect( gpointer object,
const gchar *name,
GCallback func,
gpointer func_data );
Percebeu o valor de retorno do tipo gulong? Ele é uma marca que identifica sua função de callback. Como foi dito acima, você pode ter, por sinal e por objeto, tantos callbacks quanto quiser, e todos serão executados, na ordem em que foram atribuídos.
Essa marca permite que você remova esse callback da lista, usando a função:
void g_signal_handler_disconnect( gpointer object,
gulong id );
Então, passando o widget do qual você deseja remover o tratador de sinal e a marca retornada por uma das funções signal_connect, você pode desconectar um tratador de sinal.
Você também pode temporariamente desativar tratadores de sinal com a familia de funções g_signal_handler_block() e g_signal_handler_unblock().
void g_signal_handler_block( gpointer object,
gulong id );
void g_signal_handlers_block_by_func( gpointer object,
GCallback func,
gpointer data );
void g_signal_handler_unblock( gpointer object,
gulong id );
void g_signal_handlers_unblock_by_func( gpointer object,
GCallback func,
gpointer data );
Um Hello World otimizado
[editar | editar código-fonte]Vamos dar uma olhada num "Hello World" um pouco melhorado, com melhores exemplos de callbacks. Isso nos introduzirá no próximo tópico, empacotando widgets.
#include <gtk/gtk.h>
/* Nosso novo callback melhorado. Dados passados a essa função
* são impressos na stdout. */
static void callback( GtkWidget *widget,
gpointer data )
{
g_print ("Hello again - %s foi pressionado\n", (gchar *) data);
}
/* Outra callback */
static gboolean delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit ();
return FALSE;
}
int main( int argc,
char *argv[] )
{
/* GtkWidget é o tipo de dado para widgets */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
/* Esta função é chamada em todas as aplicações GTK. Argumentos da linha
* de comando são interpretados e retornados à aplicação.*/
gtk_init (&argc, &argv);
/* Cria uma nova janela */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* Esta é uma nova chamada, que apenas muda o título da nossa
* nova janela para "Hello Buttons!"*/
gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
/* Aqui nós apenas ajustamos um tratador para delete_event que imediatamente
* sai do GTK. */
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
/* Ajusta a largura da borda da janela. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Nós criamos uma caixa para empacotar widgets nela. Descreveremos isso em detalhes
* na sessão de "empacotamento". A caixa não é realmente visível, ela
* é apenas utilizada como um instrumento para arranjar widgets. */
box1 = gtk_hbox_new (FALSE, 0);
/* Coloca a caixa na janela principal. */
gtk_container_add (GTK_CONTAINER (window), box1);
/* Cria um novo botão com o rótulo "Button 1". */
button = gtk_button_new_with_label ("Button 1");
/* Agora quando o botão é clicado, chamamos a função "callback"
* com um apontador para "button 1" como argumento */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), (gpointer) "button 1");
/* Ao invés de gtk_container_add nós empacotamos o botão na caixa invisível
* que foi colocada na janela. */
gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
/* Sempre se lembre deste passo, ele diz a GTK que nosso preparo para
* o botão esta completo, e ele pode ser exibido. */
gtk_widget_show (button);
/* Execute os mesmos passos para o segundo botão */
button = gtk_button_new_with_label ("Button 2");
/* Chame a mesma função callback com um argumento diferente,
* passando um apontador para o "button 2" dessa vez. */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), (gpointer) "button 2");
gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
/* A ordem em que os botões são exibidos não é realmente importante, mas eu
* recomento mostrar a janela por último, assim todos aparecem de uma vez. */
gtk_widget_show (button);
gtk_widget_show (box1);
gtk_widget_show (window);
/* Descanse em gtk_main e espere a diversão começar! */
gtk_main ();
return 0;
}
Compile o programa utilizando-se dos mesmos argumentos de ligação do nosso exemplo anterior. Nesse momento prevenimos que não existe um modo fácil de encerrar o programa. Você tem que usar o gerenciador de janelas ou a linha de comando para mata-lo. Bom exercício para o leitor seria criar um terceiro botão "Fechar" para encerrar o programa. Foce pode também resolver alterar as opções do gtk_box_pack_start() enquanto se prepara para a próxima sessão. Tente redimensionar a janela e observe o que acontece.