GTK+/Avançando

Origem: Wikilivros, livros abertos por um mundo aberto.

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.