Kurs GTK+ – rozdział 6

3

6. Podstawowe kontrolki

6.1. GtkCheckButton

W tym rozdziale dowiesz się nieco informacji o kilku widżetach, które można umieścić w oknie programu – jak je utworzyć oraz jak ich używać. Jednym z nich jest GtkCheckButton.

GtkCheckButton to pole zaznaczane. Przydaje się na przykład, gdy chcemy, by użytkownik wybrał, czy włączyć jakąś funkcję, czy nie. Można go utworzyć następującą funkcją:

GtkWidget* gtk_check_button_new_with_label (const gchar *label);

Jedynym parametrem jest label, czyli etykieta. Można przechwycić zdarzenie kliknięcia GtkCheckButtona – zdarzenie to nazywa się clicked. Warto również wspomnieć, że istnieje bardzo podobna do GtkCheckButton kontrolka – jest nią GtkToggleButton. Wygląda jak normalny przycisk z tym, że po wciśnięciu go pozostaje w takim stanie. GtkCheckButton tak naprawdę dziedziczy GtkToggleButton i zmienia jedynie wygląd tak powstałego widżetu. GtkToggleButton tworzy się funkcją gtk_toggle_button_new_with_label(), która również przyjmuje jako argument etykietę.

Jak już napisałem, GtkCheckButton dziedziczy GtkToggleButton, tak więc nazwy wszystkich funkcji związanych z zaznaczanym polem zaczynają się od gtk_toggle_button. Do pobierania i ustawiania stanu przycisku służą dwie funkcje:

gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button);
void gtk_toggle_button_set_active (GtkToggleButton *toggle_button, gboolean is_active);

gtk_toggle_button_get_active() pobiera wskaźnik do przycisku i zwraca TRUE, jeśli przycisk jest wciśnięty i FALSE w przeciwnym wypadku. TRUE i FALSE to wartości typowe dla GTK+, możesz jednak używać wartości typowych dla C/C++ – true i false. Druga funkcja, gtk_toggle_button_set_active() w pierwszym argumencie pobiera referencję do przycisku, a w drugim żądaną wartość – TRUE, jeśli przycisk ma być wciśnięty oraz FALSE jeżeli nie.

#include <gtk/gtk.h>

void toggle_title(GtkWidget *widget)
{
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
        gtk_button_set_label(GTK_BUTTON(widget), "Wciśnięto!");
    else
        gtk_button_set_label(GTK_BUTTON(widget), "Nie wciśnięto!");
}

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

    GtkWidget *checkButton;
    GtkWidget *toggleButton;

    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), 150, 75);
    gtk_window_set_title (GTK_WINDOW(okno), "Kurs GTK+");
    gtk_container_set_border_width (GTK_CONTAINER(okno), 5);

    vbox = gtk_vbox_new(FALSE, 1);
    gtk_container_add(GTK_CONTAINER(okno), vbox);

    checkButton = gtk_check_button_new_with_label ("Nie wciśnięto!");
    toggleButton = gtk_toggle_button_new_with_label ("Nie wciśnięto!");

    gtk_box_pack_start (GTK_BOX(vbox), checkButton, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX(vbox), toggleButton, TRUE, TRUE, 0);

    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(checkButton, "clicked", G_CALLBACK(toggle_title), NULL);
    g_signal_connect(toggleButton, "clicked", G_CALLBACK(toggle_title), NULL);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Powyższy kod ma za zadanie utworzenie okna, poznanego już kontenera GtkVBox i umieszczeniu w nim dwóch kontrolek – GtkCheckButton oraz GtkToggleButton, które po zaznaczeniu zmieniają zmieniają etykietę na „Wciśnięto!” oraz na „Nie wciśnięto!” po odznaczeniu. Efekt tego kodu można zobaczyć poniżej.

6.2. GtkFrame

GtkFrame jest ramką, której można użyć, aby pogrupować widżety. Ma 4 różne style i są to: GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN i GTK_SHADOW_ETCHED_OUT. Tworzy się ją funkcją:

GtkWidget* gtk_frame_new (const gchar *label);

Należy jej przekazać żądany tytuł dla ramki. Aby ustawić styl GtkFrame należy posłużyć się funkcją:

void gtk_frame_set_shadow_type (GtkFrame *frame, GtkShadowType type);

W pierwszym parametrze przyjmuje ona wskaźnik do ramki, a w drugim jeden z wymienionych wyżej stylów. Poniższy kod źródłowy ma za zadanie utworzyć 4 ramki, każdą z innym stylem, aby zobrazować, jak każdy z nich wygląda.

#include <gtk/gtk.h>

int main( int argc, char *argv[])
{
    GtkWidget *okno;
    GtkWidget *tabela;
    GtkWidget *ramka1;
    GtkWidget *ramka2;
    GtkWidget *ramka3;
    GtkWidget *ramka4;

    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), 250, 250);
    gtk_window_set_title(GTK_WINDOW(okno), "GtkFrame");

    gtk_container_set_border_width(GTK_CONTAINER(okno), 10);

    tabela = gtk_table_new(2, 2, TRUE);
    gtk_table_set_row_spacings(GTK_TABLE(tabela), 10);
    gtk_table_set_col_spacings(GTK_TABLE(tabela), 10);
    gtk_container_add(GTK_CONTAINER(okno), tabela);

    ramka1 = gtk_frame_new("GTK_SHADOW_IN");
    gtk_frame_set_shadow_type(GTK_FRAME(ramka1), GTK_SHADOW_IN);
    ramka2 = gtk_frame_new("GTK_SHADOW_OUT");
    gtk_frame_set_shadow_type(GTK_FRAME(ramka2), GTK_SHADOW_OUT);
    ramka3 = gtk_frame_new("GTK_SHADOW_ETCHED_IN");
    gtk_frame_set_shadow_type(GTK_FRAME(ramka3), GTK_SHADOW_ETCHED_IN);
    ramka4 = gtk_frame_new("GTK_SHADOW_ETCHED_OUT");
    gtk_frame_set_shadow_type(GTK_FRAME(ramka4), GTK_SHADOW_ETCHED_OUT);

    gtk_table_attach_defaults(GTK_TABLE(tabela), ramka1, 0, 1, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(tabela), ramka2, 0, 1, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(tabela), ramka3, 1, 2, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(tabela), ramka4, 1, 2, 1, 2);

    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, zobaczysz coś takiego:

6.3. GtkLabel

GtkLabel pozwala tworzyć etykiety. I to nie byle jakie. Daje możliwość nie tylko wprowadzenia czystego tekstu, ale również sformatowanie go za pomocą języka znaczników w pewnym stopniu podobnego do HTMLa. Lista obsługiwanych znaczników znajduje się na stronie dokumentacji GTK+.

Poniższa funkcja tworzy nową etykietę:

GtkWidget* gtk_label_new (const gchar *str);

W argumencie należy przekazać żądany tekst. Aby jednak go sformatować, należy użyć funkcji:

void gtk_label_set_markup (GtkLabel *label, const gchar *str);

W pierwszym argumencie należy przekazać referencję do widżetu, a w drugim – tekst napisany we wspomnianym języku znaczników – Pango Text Attribute Markup Language,

Przykład:

#include <gtk/gtk.h>

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

    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_title(GTK_WINDOW(okno), "Kurs GTK+");

    char *str = "<sub>Ten</sub> <tt>tekst</tt> <span underline='error'>został</span> <span font='20'>napisany</span> <span bgcolor='#f00'>różnymi</span> <b><i>stylami</i></b>.";

    etykieta = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(etykieta), str);

    gtk_label_set_justify(GTK_LABEL(etykieta), GTK_JUSTIFY_CENTER);
    gtk_container_add(GTK_CONTAINER(okno), etykieta);
    gtk_widget_show(etykieta);

    gtk_window_set_default_size(GTK_WINDOW(okno), 350, 100);

    g_signal_connect(okno, "destroy", G_CALLBACK (gtk_main_quit), NULL);

    gtk_widget_show(okno);

    gtk_main();

    return 0;
}

Efekt działania programu powstałego po skompilowaniu powyższego kodu jest następujący:

6.4. GtkComboBox

GtkComboBox to lista rozwijana. Może się przydać, gdy chcemy dać wybór użytkownikowi jednej z kilku opcji – np. wybór miesiąca w kalendarzu. Tworzy się go następującą funkcją:

GtkWidget* gtk_combo_box_text_new (void);

Tworzy ona jednak nie GtkComboBoksa, a GtkComboBoxText. Różni się on od GtkComboBoksa tym, że wszystkie jego elementy muszą być w postaci tekstu – GtkComboBox daje np. możliwość stworzenia drzewa.

Aby więc dodać element do GtkComboBoxText, należy posłużyć się funkcją:

void gtk_combo_box_append_text (GtkComboBox *combo_box, const gchar *text);

W pierwszym argumencie przyjmuje ona referencję do Combo boksa, a w drugim żądany tekst.

Warto powiedzieć, że po wybraniu którejś opcji przez użytkownika, zostaje wywołane zdarzenie „changed”.

Poniższy kod ma za zadanie stworzyć listę rozwijaną, a po wybraniu którejś opcji przez użytkownika, zmienić tekst w etykiecie.

#include <gtk/gtk.h>

void combo_selected(GtkWidget *widget, gpointer etykieta)
{
    gchar *text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget));
    gtk_label_set_text(GTK_LABEL(etykieta), text);
    g_free(text);
}

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

    gtk_init(&argc, &argv);

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

    vbox = gtk_vbox_new(FALSE, 1);
    gtk_container_add(GTK_CONTAINER(okno), vbox);

    etykieta = gtk_label_new("Wybierz miesiąc:");
    gtk_container_add(GTK_CONTAINER(vbox), etykieta);

    combobox = gtk_combo_box_new_text();
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Styczeń");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Luty");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Marzec");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Kwiecień");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Maj");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Czerwiec");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Lipiec");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Sierpień");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Wrzesień");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Październik");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Listopad");
    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "Grudzień");

    gtk_container_add(GTK_CONTAINER(vbox), combobox);

    etykieta2 = gtk_label_new("");
    gtk_container_add(GTK_CONTAINER(vbox), etykieta2);

    g_signal_connect(G_OBJECT(okno), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(combo_selected), (gpointer)etykieta2);

    gtk_widget_show_all(okno);

    gtk_main();

    return 0;
}

Efekt jego działania można zobaczyć poniżej.


6.5. GtkEntry

Ostatnim z widżetów prezentowanych w tym rozdziale jest GtkEntry. Jest to pole tekstowe, do którego użytkownik może wpisywać jakieś dane. Tworzy się go funkcją:

GtkWidget* gtk_entry_new (void);

Poniższy kod źródłowy ma za zadanie utworzyć etykietę oraz pole tekstowe.

#include <gtk/gtk.h>

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

    gtk_init(&argc, &argv);

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

    vbox = gtk_vbox_new(FALSE, 1);
    gtk_container_add(GTK_CONTAINER(okno), vbox);

    etykieta = gtk_label_new("Wpisz poniżej swoje imię:");
    gtk_container_add(GTK_CONTAINER(vbox), etykieta);

    entry = gtk_entry_new();
    gtk_container_add(GTK_CONTAINER(vbox), entry);

    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:

To by było na tyle w tym rozdziale. W następnym temat widżetów będzie kontynuowany.

3 komentarze

  1. Mateusz

    Świetna część tutorialu. Jeszcze nie wszystko mi wyszło, ale próbuję doprowadzić moją wizję widgetu do porządku. Oczywiście mam już wizje na jego rozwój i czekam z niecierpliwością na kolejną część tutka 🙂

    Odpowiedz
    • m4tx

      admin

      Świetna część tutorialu.

      Wielkie dzięki 🙂

      czekam z niecierpliwością na kolejną część tutka 🙂

      Dzisiaj powinien być następny rozdział. Fajnie wiedzieć, że ktoś to czyta. Jeszcze raz dzięki 😛

      Odpowiedz
  2. Lukines

    Tak czyta czyta ;)) Bardzo dobry kurs. Oby więcej takich Gratulacje ;D

    Odpowiedz

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>