GTK+/Szkielet programu GTK+ w języku C++

Dzięki cudownym właściwościom języka C++ (wsteczna kompatybilność z językiem C) możemy beż problemy używać bibliotek GTK+ pisząc aplikacje w C++. Utworzymy trzy pliki z kodem, a naszą klasę nazwiemy MyGUI. Pierwszy to deklaracja klasy MyGUI.hpp, następnie MyGUI.cpp gdzie znajduje się definicja metod klasy (część z nich jest funkcjami zwrotnymi dla kontrolek GTK+). Główny plik będzie zawierał tylko obsługę naszej klasy MyGUI.


Plik MyGUI.hpp


#include <gtk/gtk.h>
#include <iostream>
#include <string>

using namespace std; 


class MyGUI
{
  private:
    GtkWidget *window;
    GtkWidget *button;
    string programtitle;

    static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data);
    static void destroy(GtkWidget *widget, gpointer data);
    static void buttonclicked(GtkWidget *widget, gpointer data);

  public:
    MyGUI();
    ~MyGUI();
    void init(int, char**);
    void build();
    void run();
};

Klasa przechowuje wskaźniki do tworzonych kontrolek oraz funkcje zwrotne (zwróć uwagę na to, iż muszą być zadeklarowane jako statyczne - ponieważ GTK+ musi mieć do nich dostęp) w sekcji private. Znajduje się tu też zmienna klasy string. Natomiast w sekcji public posiadamy standardowo konstruktor oraz destruktor oraz trzy funkcje. Funkcje te realizują odpowiednio następujące zadania; zainicjowanie maszyny GTK+, tworzenie okna i kontrolek wraz z podpinaniem do nich funkcji zwrotnych, tworzenie widocznym stworzonych kontrolek oraz uruchamianie samej maszyny GTK+. Podział tych zadań wynika wyłącznie z koncepcji, nic nie stoi na przeszkodzie aby cały ten kod umieścić w jednej funkcji.


Plik MyGUI.cpp


#include "MyGUI.hpp"


MyGUI::MyGUI()
{
  cout << "Konstruktor" << endl;
}

MyGUI::~MyGUI()
{
  cout << "Destruktor" << endl;
}

void MyGUI::init(int argc, char** argv)
{
  gtk_init(&argc, &argv);
}

void MyGUI::build()
{
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
  g_signal_connect(G_OBJECT(window),"delete_event",G_CALLBACK(delete_event),this);
  g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(destroy),this);
 
  gtk_window_set_title(GTK_WINDOW(window),"MyGUI");
  gtk_widget_set_size_request(window,170,50);
  gtk_container_set_border_width(GTK_CONTAINER(window),10);

  button = gtk_button_new_with_label("PressMy");
  g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(buttonclicked),this);
  gtk_container_add(GTK_CONTAINER(window),button);
}

void MyGUI::run()
{
  gtk_widget_show_all(window);
  gtk_main();
}

gboolean MyGUI::delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  return FALSE;
}

void MyGUI::destroy(GtkWidget *widget, gpointer data)
{
  gtk_main_quit();
}

void MyGUI::buttonclicked(GtkWidget *widget, gpointer data)
{
  MyGUI *mygui = static_cast<MyGUI*>(data);
  
  cout << gtk_button_get_label(GTK_BUTTON(mygui->button)) << endl;
  mygui->programtitle = gtk_window_get_title(GTK_WINDOW(mygui->window));
  cout << "Nazwa twojego programu to: " << mygui->programtitle << endl;
}

W tym pliku najbardziej interesującą rzeczą jest sposób przekazywania danych z klasy do funkcji zwrotnych. Zwróć uwagę na łączenie sygnałów. Do dodatkowych danych funkcji zwrotnej - gpointer user_data - jest przekazywany wskaźnik this. Natomiast w funkcji zwrotnej buttonclicked() widać jak go rzutujemy na oryginalny typ MyGUI aby mieć dostęp do danych zawartych w naszej klasie, przycisku oraz zmiennej klasy string.


Plik main.cpp


#include "MyGUI.cpp"

int main(int argc, char *argv[])
{
  MyGUI *gui = new MyGUI;
  
  gui->init(argc,argv);
  gui->build();
  gui->run();
  
  delete gui;
  
  return 0;
}

Ostatecznie tworzymy nowy obiekt naszej klasy i wywołujemy w odpowiedniej kolejności funkcje tworzące interfejs.


Na koniec przyda nam się plik Makefile:

CC = g++

CFLAGS = -Wall			 	\
	-DG_DISABLE_DEPRECATED 	 	\
	-DGDK_DISABLE_DEPRECATED 	\
	-DGDK_PIXBUF_DISABLE_DEPRECATED \
	-DGTK_DISABLE_DEPRECATED

kalkulator: main.cpp
	$(CC) main.cpp -o mygui $(CFLAGS) `pkg-config gtk+-2.0 --cflags --libs`

clean: 
	rm -f *.o mygui

Teraz aby skompilować nasz program wystarczy wpisać:
$ make
ponowna kompilacja to:
$ make clean
$ make
Oczywiście jeżeli używa się systemu Linux.