baseado no Getting Started do gtk.org

Introdução

O GTK é um kit de ferramentas de código aberto para o desenvolvimento de programas com interfaces gráficas na linguagem C, também pode ser utilizada em outras linguagens, nesse post vou explicar o funcionamento de um programa de exemplo, Hello World.

O Básico

A interface criada pelo GTK e baseada em orientação a objetos, portanto cada um dos elementos possui uma serie de características, os elementos são organizados de forma hierárquica, por exemplo uma janela que contenha um botão que contenha um texto. Uma interface é criada ao adicionarmos a uma janela outros elemento, como botões, textos, menus, etc.

Instalação

Linux

na documentação do GTK indica a instalação através da instalação dos pacotes pelo código fonte, porem no ubuntu 20.04 ele já vem instalado, se você quiser confirmar pode executar o seguinte comando.

sudo apt install libgtk-3-dev

também e necessário ter um compilador de C instalado na sua maquina, no linux o GCC, que pode ser facilmente instalado utilizando o seguinte comando.

sudo apt install gcc

Hello World

Para começar a entender o funcionamento vamos dissecar o código fonte do hello world, para começar vamos criar um programa em c padrão e adicionando a biblioteca do GTK.

#include <gtk/gtk.h>

int main(int argc, char **argv){
    return 0;
}

Em um aplicativo GTK a função main() tem a função criar um objeto GtkApplication e executa-lo, no exemplo ela é criada e inicializada utilizando a função gtk_application_new() que recebe como parâmetros o identificador do programa e o acesso do programa ao sistema.

Ao criar uma aplicação GTK GtkApplication é necessário escolher um id (nome) como parâmetro, para o exemplo org.gtk.example, esse identificador deve ser único senão causara problemas, também é necessário informar o GApplicationFlags que é o acesso que o programa necessitara ao sistema como a arquivos no exemplo não e necessário nenhum acesso, vamos dar uma olhada na função main().

1   int main(int argc, char **argv){
2       GtkApplication *app;
3       int status;
4       
5       app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); //Cria a aplicação
6       g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); //conecta o sinal de a função
7       status = g_application_run (G_APPLICATION (app), argc, argv); // inicia o app
8       g_object_unref (app);
9       
10      return status;
11  }

Na linha 5 temos a criação da aplicação GTK app como o identificador e as flags fornecidas, na linha seguinte o sinal de ativação e conectada a função de call back activate() que sera chamada quando o aplicativo for iniciado pela função g_application_run(), essa função recebo como paramentos a G_APPLICATION(app) e os ponteiros para argumentos da linha de comando para que possam ser analisados pelo GTK e os que forrem reconhecidos como argumentos do GTK serão removido e os argumentos restantes serão enviados para a sua aplicação. Agora que a aplicação já foi iniciada pela g_application_run() vamos a função activate() que sera responsável por criar a janela e seus elementos.

1   static void activate(GtkApplication *app, gpointer user_data){
2     GtkWidget *window;
3     GtkWidget *button;
4     GtkWidget *button_box;
5
6     window = gtk_application_window_new(app); // Cria a janela
7     gtk_window_set_title(GTK_WINDOW (window), "Window"); //define o titulo 
8     gtk_window_set_default_size(GTK_WINDOW (window), 200, 200); //define o tamanho 
9
10    button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
11    gtk_container_add(GTK_CONTAINER(window), button_box);
12
13    button = gtk_button_new_with_label("Hello World");
14    g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
15    g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), window);
16    gtk_container_add(GTK_CONTAINER(button_box), button);
17
18    gtk_widget_show_all(window);
19  }

Na linha 6 a função gtk_application_window_new() cria uma janela e a armazena dentro do ponteiro window, depois a janela tem o titulo definido na função gtk_window_set_title() que receba a janela em que o titulo deve ser definido e uma string com o titulo, na linha seguinte o tamanho inicial e definido em gtk_window_set_default_size() que de novo recebe a janela a ter o valor definido e os valores de largura e altura em pixels.

Note que nas ultimas duas funções ao enviarmos a janela em que queremos modificar alguma propriedade adicionamos o ponteiro a função GTK_WINDOW() que converte o ponteiro GtkWidget em ponteiro GtkWindow.

Elementos da janela

Os elementos da janela são definidos nas linhas 10 a 13, no caso um botão e um texto que é adicionado no interior do botão, um elemento filho.

Primeiro precisamos definir a button_box que é uma variável utilizada pelo GTK para controlar o tamanho dos elementos, o button_box é criado pela função gtk_button_box_new() que recebe como paramento a orientação do elemento, os botoes que essa caixa conterá podem ser armazenados com orientação horizontal ou vertical, porem como nesse exemplo estamos lidando apenas com um botão não faz diferença, apos inicializar o button_box ele é adicionado ao widget da janela pela função gtk_container_add().

agora que temos uma botton_box na janela podemos criar um botão com texto (label) pela função gtk_button_new_with_label() que retorna a GtkButton a ser armazenada na button, agora podemos adicionar alguma utilidade ao botão, através da função g_signal_connect() conectamos um sinal que sera enviado pelo botão ao ser clicado a uma função no caso print_hello(), como a nossa função não utiliza nenhum dado de entrada, NULL e passado para ela, também conectamos também o click do nosso botão ao fechamento da janela chamando a função gtk_widget_destroy e enviando para ela qual janela deve ser fechada, agora podemos adicionar o botão a button_box pela função gtk_container_add().

Por fim a função gtk_widget_show_all() ira mostrar a janela com seu elementos.

Voltando a main

Quando o programa e fechado e a variável status recebe um numero inteiro, depois o objeto GtkApplication é liberado da memoria pela função g_object_unref() e o status do app e retornado ao sistema, se algum erro aconteceu sera envidado para o sistema pelo return do programa.

Compilando um programa GTK

para compilar e necessário informar ao compilador aonde ele pode encontrar os arquivos da biblioteca GTK no ubuntu basta executar esse comando do arquivo no mesmo diretório do arquivo .c, lembrado de substituir o nome do arquivo.

gcc `pkg-config --cflags gtk+-3.0` -o hello-world-gtk hello-world-gtk.c `pkg-config --libs gtk+-3.0`

lembre-se que a documentação original e a sua melhor fonte

Código completo

#include <gtk/gtk.h>

static void print_hello (GtkWidget *widget, gpointer data){
  g_print ("Hello World\n");
}

static void activate(GtkApplication *app, gpointer user_data){
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *button_box;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Window");
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

  button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_container_add (GTK_CONTAINER (window), button_box);

  button = gtk_button_new_with_label ("Hello World");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
  g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
  gtk_container_add (GTK_CONTAINER (button_box), button);

  gtk_widget_show_all (window);
}

int main(int argc, char **argv){
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}