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.