Kurs GTK+ – rozdział 9

0

9. Dialogi

9.1. GtkMessageDialog

W tym rozdziale dowiesz się, jak tworzyć i używać dialogów w GTK+.

Pierwszym typem dialogów, jaki chciałbym omówić, to dialogi informacyjne. Charakteryzują się tym, że zazwyczaj nie pobierają żadnych informacji od użytkownika, a ich głównym celem jest powiadomienie użytkownika o czymś, co nastąpiło. Tworzy się je funkcją:

GtkWidget* gtk_message_dialog_new (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar *message_format, ...);

Pierwszym parametrem jest rodzic okna (można ustawić NULL). Następnym są flagi, których listę można znaleźć na stronie dokumentacji GTK+. W kolejnym argumencie należy podać typ dialogu – ich listę również można znaleźć na stronie dokumentacji. Kolejnym są żądane przyciski. Ich listę także można znaleźć w dokumentacji. W ostatnim argumencie należy podać tytuł. Warto wspomnieć, że powyższą funkcją można go sformatować podobnie jak funkcją printf().

Dialog uruchamia funkcja:

gint gtk_dialog_run (GtkDialog *dialog);

Która jako argument przyjmuje referencję do dialogu.

Poniższy kod źródłowy utworzy okno z przyciskiem, po kliknięciu którego otworzy się dialog informacyjny.

#include <gtk/gtk.h>

void pokaz_dialog(GtkWidget *widget, gpointer okno)
{
    GtkWidget *dialog;
    dialog = gtk_message_dialog_new(GTK_WINDOW(okno), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Wystąpił błąd: %s", "nie można otworzyć pliku!");
    gtk_window_set_title(GTK_WINDOW(dialog), "Błąd");
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
}

int main(int argc, char *argv[])
{
    GtkWidget *okno;
    GtkWidget *przycisk;

    gtk_init(&argc, &argv);

    okno = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(okno), 200, 100);
    gtk_window_set_title(GTK_WINDOW(okno), "Kurs GTK+");

    przycisk = gtk_button_new_with_label("Dialog");

    gtk_container_add(GTK_CONTAINER(okno), przycisk);
    gtk_container_set_border_width(GTK_CONTAINER(okno), 15);

    g_signal_connect(G_OBJECT(przycisk), "clicked", G_CALLBACK(pokaz_dialog), (gpointer)okno);
    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Jego działanie jest następujące:

9.2. GtkAboutDialog

GtkAboutDialog to bardzo popularny dialog, który można znaleźć w bardzo wielu programach – jest to dialog „O programie”. Tworzy się go funkcją:

GtkWidget* gtk_about_dialog_new (void);

Wywołanie jedynie powyższej funkcji da niezbyt ciekawy efekt. Aby dialog urozmaicić, można użyć poniższych funkcji:

void gtk_about_dialog_set_name (GtkAboutDialog *about, const gchar *name);
void gtk_about_dialog_set_version (GtkAboutDialog *about, const gchar *version);
void gtk_about_dialog_set_copyright (GtkAboutDialog *about, const gchar *copyright);
void gtk_about_dialog_set_comments (GtkAboutDialog *about, const gchar *comments);
void gtk_about_dialog_set_website (GtkAboutDialog *about, const gchar *website);

Nie ma sensu omawiać każdej z osobna, dlatego powiem tylko, co każda z nich robi. Pierwsze ustawia nazwę programu wyświetlaną w dialogu, druga wersję, trzecia ustawia właściciela praw autorskich, następna krótki opis programu i ostatnia – stronę internetową. Każda z nich posiada takie same argumenty. Pierwszym jest wskaźnik do dialogu, a drugim żądany ciąg znaków.

Warto jeszcze powiedzieć, że do dialogu „O programie” można dodać logo. W tym celu należy utworzyć zmienną typu GdkPixbuf i załadować do niej logo programu, a następnie za pomocą funkcji:

void gtk_about_dialog_set_logo (GtkAboutDialog *about, GdkPixbuf *logo);

Która w pierwszym argumencie przyjmuje referencję do dialogu, a w drugim do zmiennej typu GdkPixbuf, dodać logo do dialogu. Należy też zwolnić pamięć po logo, posługując się funkcją:

void g_object_unref (gpointer object);

Przykład jej użycia w kodzie źródłowym tworzącym okno „O programie” znajduje się poniżej.

#include <gtk/gtk.h>

void pokaz_dialog(GtkWidget *widget, gpointer okno)
{
    GtkWidget *dialog = gtk_about_dialog_new();
    GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file("smsprice.png", NULL);

    gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), "SmsPrice");
    gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), "1.0");
    gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "(c) Mateusz \"m4tx\" M.");
    gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), "SmsPrice to program sprawdzający cenę wysłania wiadomości na podany numer SMS Premium.");
    gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://www.m4tx.pl/");
    gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf);
    g_object_unref(pixbuf), pixbuf = NULL;
    gtk_dialog_run(GTK_DIALOG (dialog));
    gtk_widget_destroy(dialog);
}

int main(int argc, char *argv[])
{
    GtkWidget *okno;
    GtkWidget *przycisk;

    gtk_init(&argc, &argv);

    okno = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(okno), 200, 100);
    gtk_window_set_title(GTK_WINDOW(okno), "Kurs GTK+");

    przycisk = gtk_button_new_with_label("Dialog");

    gtk_container_add(GTK_CONTAINER(okno), przycisk);
    gtk_container_set_border_width(GTK_CONTAINER(okno), 15);

    g_signal_connect(G_OBJECT(przycisk), "clicked", G_CALLBACK(pokaz_dialog), (gpointer)okno);
    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Po skompilowaniu i uruchomieniu programu powinieneś zobaczyć coś takiego:

9.3. GtkFontSelectionDialog

GtkFontSelectionDialog to okno wyboru czcionki. Może się przydać chociażby przy pisaniu edytora tekstu. GtkFontSelectionDialog tworzy się funkcją:

GtkWidget* gtk_font_selection_dialog_new (const gchar *title);

Funkcja ta przyjmuje jako argument żądany tytuł okna. Aby jednak zmienić czcionkę w wybranym widżecie, należy posłużyć się poniższymi funkcjami:

gchar* gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd);
PangoFontDescription* pango_font_description_from_string (const char *str);
void gtk_widget_modify_font (GtkWidget *widget, PangoFontDescription *font_desc);

Pierwsza z nich zamienia nazwę i właściwości wybranej czcionki na tekst. Następna zamienia ten tekst na zmienną typu PangoFontDescription. Ostatnia ustawia żądanemu widżetowi czcionkę.

Warto również wiedzieć, który z przycisków – OK czy Anuluj w dialogu wyboru czcionki wcisnął użytkownik. Należy do tego wykorzystać zmienną typu GtkResponseType, która zwracana jest przez funkcję gtk_dialog_run(). Listę zwracanych wartości można znaleźć w dokumentacji GTK+.

Poniższy kod źródłowy pokazuje, jak utworzyć dialog wyboru czcionki oraz zmienić czcionkę etykiety na tę wybraną w dialogu.

#include <gtk/gtk.h>

void pokaz_dialog(GtkWidget *widget, gpointer etykieta)
{
    GtkResponseType wynik;

    GtkWidget *dialog = gtk_font_selection_dialog_new("Select Font");
    wynik = (GtkResponseType)gtk_dialog_run(GTK_DIALOG(dialog));

    if (wynik == GTK_RESPONSE_OK || wynik == GTK_RESPONSE_APPLY)
    {
        PangoFontDescription *czcionka;
        gchar *nazwa_czcionki = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(dialog));

        czcionka = pango_font_description_from_string(nazwa_czcionki);

        gtk_widget_modify_font(GTK_WIDGET(etykieta), czcionka);

        g_free(nazwa_czcionki);
    }

    gtk_widget_destroy(dialog);
}

int main(int argc, char *argv[])
{
    GtkWidget *okno;
    GtkWidget *przycisk;
    GtkWidget *etykieta;
    GtkWidget *vbox;

    gtk_init(&argc, &argv);

    okno = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(okno), 200, 100);
    gtk_window_set_title(GTK_WINDOW(okno), "Kurs GTK+");

    przycisk = gtk_button_new_with_label("Dialog");
    etykieta = gtk_label_new("Tekst");

    vbox = gtk_vbox_new(FALSE, 3);

    gtk_container_add(GTK_CONTAINER(okno), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), etykieta, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), przycisk, TRUE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(okno), 15);

    g_signal_connect(G_OBJECT(przycisk), "clicked", G_CALLBACK(pokaz_dialog), (gpointer)etykieta);
    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Jego działanie jest następujące:

9.4. GtkColorSelectionDialog

GtkColorSelectionDialog to dialog wyboru koloru. Tworzy się go funkcją:

GtkWidget* gtk_color_selection_dialog_new (const gchar *title);

W argumencie przyjmuje ona żądany tytuł okna. Aby pobrać kolor wybrany przez użytkownika należy posłużyć się funkcją:

void gtk_color_selection_get_current_color (GtkColorSelection *colorsel, GdkColor *color);

W pierwszym argumencie przyjmuje ona zmienną typu GtkColorSelection, którą można pobrać stosując poniższą kontrukcję:

GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel)

Natomiast w drugim argumencie – wyjściowym – należy podać wskaźnik do zmiennej typu GdkColor.

Wszelkie wątpliwości powinien rozwiać poniższy kod źródłowy. Utworzony przycisk otwiera dialog, który po wybraniu koloru i zatwierdzeniu, zmienia kolor etykiety.

#include <gtk/gtk.h>

void pokaz_dialog(GtkWidget *widget, gpointer etykieta)
{
    GtkResponseType wynik;

    GtkWidget *dialog = gtk_color_selection_dialog_new("Wybierz kolor");
    wynik = (GtkResponseType)gtk_dialog_run(GTK_DIALOG(dialog));

    if (wynik == GTK_RESPONSE_OK)
    {
        GdkColor kolor;
        GtkColorSelection *wybrany_kolor;

        wybrany_kolor = GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel);
        gtk_color_selection_get_current_color(wybrany_kolor, &kolor);
        gtk_widget_modify_fg(GTK_WIDGET(etykieta), GTK_STATE_NORMAL, &kolor);
    }

    gtk_widget_destroy(dialog);
}

int main(int argc, char *argv[])
{
    GtkWidget *okno;
    GtkWidget *przycisk;
    GtkWidget *etykieta;
    GtkWidget *vbox;

    gtk_init(&argc, &argv);

    okno = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(okno), 200, 100);
    gtk_window_set_title(GTK_WINDOW(okno), "Kurs GTK+");

    przycisk = gtk_button_new_with_label("Dialog");
    etykieta = gtk_label_new("Tekst");

    vbox = gtk_vbox_new(FALSE, 3);

    gtk_container_add(GTK_CONTAINER(okno), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), etykieta, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), przycisk, TRUE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(okno), 15);

    g_signal_connect(G_OBJECT(przycisk), "clicked", G_CALLBACK(pokaz_dialog), (gpointer)etykieta);
    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Po skompilowaniu i uruchomieniu w ten sposób powstałego programu, powinieneś zobaczyć:

9.5. GtkFileChooserDialog

GtkFileChooserDialog to jeden z bardziej przydatnych dialogów. Jest to bowiem dialog wyboru pliku. Może się więc przydać w przeróżnych programach – edytorach tekstu, obrazów, czy nawet w grach. GtkFileChooserDialog tworzy się funkcją:

GtkWidget* gtk_file_chooser_dialog_new (const gchar *title, GtkWindow *parent, GtkFileChooserAction action, const gchar *first_button_text, ...);

W pierwszym argumencie należy podać żądany tytuł dialogu. W następnym wskaźnik do rodzica. W kolejnym należy podać typ dialogu – otwarcie pliku, zapisanie, wybór lub utworzenie katalogu – ich lista dostępna jest w dokumentacji GTK+. W kolejnych argumentach należy podać kolejno etykietę przycisku (warto zaznaczyć, że można podać ID elementu z opisywanego już stocku) oraz odpowiedź zwracaną po wciśnięciu tego przycisku – kilkukrotnie, w zależności od żądanej ilości przycisków w dialogu. W ostatnim argumencie należy podać NULL.

Warto również wiedzieć, jak pobrać ścieżkę do pliku lub folderu wybranego przez użytkownika. Służy do tego funkcja:

gchar* gtk_file_chooser_get_filename (GtkFileChooser *chooser);

Należy przekazać jej referencję do dialogu.

Warto znać również jeszcze dwie przydatne funkcje:

gboolean gtk_file_chooser_get_current_folder (GtkFileChooser *chooser, const gchar *folder);
void gtk_file_chooser_set_current_name (GtkFileChooser *chooser, const gchar *name);

Pierwsza z nich ustawia domyślnie otwarty katalog, natomiast druga – domyślną nazwę pliku. Obie funkcje w pierwszym argumencie przyjmują wskaźnik do dialogu, a w drugim ciąg znaków – ścieżkę do folderu, lub nazwę pliku.

Poniższy kod źródłowy ma za zadanie utworzenie okna z przyciskiem i etykietą. Po wciśnięciu przycisku otwiera się dialog, w którym można wybrać plik, do którego ścieżka będzie wyświetlać się w etykiecie.

#include <gtk/gtk.h>

GtkWidget *etykieta;

void pokaz_dialog(GtkWidget *widget, gpointer okno)
{
    GtkWidget *dialog;

    dialog = gtk_file_chooser_dialog_new ("Otwórz...", GTK_WINDOW(okno), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);

    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
    {
        char *nazwa_pliku;

        nazwa_pliku = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
        gtk_label_set_text(GTK_LABEL(etykieta), nazwa_pliku);
        g_free (nazwa_pliku);
    }

    gtk_widget_destroy (dialog);
}

int main(int argc, char *argv[])
{
    GtkWidget *okno;
    GtkWidget *przycisk;
    GtkWidget *vbox;

    gtk_init(&argc, &argv);

    okno = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(okno), 200, 100);
    gtk_window_set_title(GTK_WINDOW(okno), "Kurs GTK+");

    przycisk = gtk_button_new_with_label("Dialog");
    etykieta = gtk_label_new("Tekst");

    vbox = gtk_vbox_new(FALSE, 3);

    gtk_container_add(GTK_CONTAINER(okno), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), etykieta, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), przycisk, TRUE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(okno), 15);

    g_signal_connect(G_OBJECT(przycisk), "clicked", G_CALLBACK(pokaz_dialog), (gpointer)okno);
    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Działanie tego kodu jest następujące:

To koniec tego rozdziału. Następny omawia motywy.

Zostaw komentarz

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>