Prohlížeč obrázků (C) O trošku složitější aplikace Gtk než jednoduché „Hello world“. Dokumentační projekt GNOME gnome-doc-list@gnome.org Johannes Schmid jhs@gnome.org Marta Maria Casetti mmcasetti@gmail.com 2013 Prohlížeč obrázků

V této lekci se seznámíme s následujícími věcmi:

Některými základními koncepty programování v C s GObject

Jak psát aplikaci Gtk v C

Vytvoření projektu ve studiu Anjuta

Než začnete s kódováním, musíte ve studiu Anjuta vytvořit nový projekt. Tím se vytvoří všechny soubory, které budete později potřebovat k sestavení a spuštění kódu. Je to také užitečné kvůli udržení všeho pohromadě.

Spusťte IDE Anjuta a klikněte na Soubor Nový Projekt, aby se otevřel průvodce projektem.

Na kartě C zvolte GTK+ (jednoduchý), klikněte na Pokračovat a na několika následujících stránkách vyplňte své údaje. Jako název projektu a složky použijte image-viewer.

Ujistěte se, že Použít GtkBuilder k tvorbě uživatelského rozhraní je vypnuto, protože jej chceme v této lekci vytvořit ručně. Jestli se chcete naučit, jak používat návrhář uživatelského rozhraní, podívejte se do lekce Kytarová ladička.

Klikněte na Použít a vytvoří se vám projekt. Otevřete src/main.c na kartě Projekt nebo Soubor. Měli byste vidět kód, který začíná řádky:

#include <config.h> #include <gtk/gtk.h>
Prvotní sestavení kódu

C je celkem „upovídaný“ jazyk, takže nebuďte překvapeni, že soubor obsahuje poměrně hodně kódu. Většina toho je kód šablony. Načte (prázdné) okno a zobrazí jej. Dále to podrobněji rozebereme. Pokud jste již pochopili základy, tak tento seznam můžete přeskočit:

Tři řádky #include na začátku vkládají knihovny config (užitečné definice pro sestavení pomocí autotools), gtk (uživatelské rozhraní) a gi18n (internacionalizace). Funkce z těchto knihoven se používají ve zbytku kódu.

Funkce create_window vytvoří nové (prázdné) okno a napojí signál, který zajistí ukončení aplikace, když je zavřeno okno.

Napojení signálu je způsob, jak definovat, co se má stát, když zmáčknete tlačítko nebo se prostě něco přihodí. Zde je zavolána metoda destroy (a ukončení aplikace) při zavření okna.

Funkce main se spustí jako výchozí, když spustíte aplikaci napsanou v jazyce C. Volá pár funkcí, které nastaví a spustí aplikaci. Funkce gtk_main spustí hlavní smyčku GTK, která spustí uživatelské rozhraní a začne naslouchat událostem (jako je kliknutí nebo zmáčknutí klávesy).

Podmíněná definice ENABLE_NLS nastavuje gettext, což je základní konstrukce pro překládání aplikací do národních jazyků. Tyto funkce určují, jak mají překladové nástroje pracovat s vaší aplikací za běhu.

Kód je připravený k použití, takže jej můžete zkompilovat kliknutím na Sestavit Sestavit projekt (nebo zmáčknutím Shift F7).

V následujícím okně zmáčkněte Spustit, aby se nakonfigurovalo ladicí sestavení. Stačí to udělat jen jednou, pro první sestavení.

Vytvoření uživatelského rozhraní

Nyní prázdné okno oživíme. GTK uspořádává uživatelské rozhraní pomocí widgetů GtkContainer, které mohou obsahovat další widgety i další kontejnery. Zde použijeme nejjednodušší dostupný kontejner GtkBox:

static GtkWidget* create_window (void) { GtkWidget *window; GtkWidget *button; GtkWidget *image; GtkWidget *box; /* Vytvoří uživatelské rozhraní */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "image-viewer-c"); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); button = gtk_button_new_with_label (_("Open image")); image = gtk_image_new (); gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (window), box); /* Napojí signály */ /* Při otevírání souboru zobrazí dialogové okno pro výběr souboru */ g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image); /* Skončit, když je zavřeno okno */ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); return window; }

První řádek vytvoří widgety, které potřebujeme použít: tlačítko pro otevření obrázku, widget pro vlastní zobrazení obrázku a box, který použijeme jako kontejner. Makra, jako je GTK_BOX se používají pro dynamické typovou kontrolu a přetypování, což je potřeba, protože C nepodporuje samo o sobě objektově orientované programování.

Volání gtk_box_pack_start přidává dva widgety do boxu a definuje jejich chování. Obrázek se roztáhne přes veškeré dostupné místo, zatímco tlačítko bude jen tak velké, jak je potřeba. Všimněte si, že jsme u widgetů výslovně nenastavili velikost. GTK to obvykle nepotřebuje, což usnadňuje udělat rozvržení, které vypadá dobře při různých velikostech okna. Následně je box přidán do okna.

Potřebujeme nadefinovat, co se stane, když uživatel klikne na tlačítko. GTK používá koncept signálů. Když je kliknuto na tlačítko, spustí se signál clicked, který můžeme napojit na nějakou akci. To se udělá pomocí funkce g_signal_connect, která řekne GTK, aby zavolalo funkci on_image_open, když je na tlačítko kliknuto a předalo funkci obrázek jako dodatečný argument. Funkci zpětného volání nadefinujeme v další části.

Poslední g_signal_connect() zajistí, že se aplikace ukončí při zavření okna.

Jako poslední krok zajistěte nahrazení volání gtk_widget_show ve funkci main() za gtk_widget_show_all(), aby se zobrazilo okno a všechny widgety v něm.

Zobrazení obrázku

Nyní nadefinujeme obsluhu signálu pro signál clicked tzn. pro tlačítko zmíněné dříve. Přidejte tento kód před metodu create_window().

static void on_open_image (GtkButton* button, gpointer user_data) { GtkWidget *image = GTK_WIDGET (user_data); GtkWidget *toplevel = gtk_widget_get_toplevel (image); GtkFileFilter *filter = gtk_file_filter_new (); GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open image"), GTK_WINDOW (toplevel), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); gtk_file_filter_add_pixbuf_formats (filter); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); switch (gtk_dialog_run (GTK_DIALOG (dialog))) { case GTK_RESPONSE_ACCEPT: { gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gtk_image_set_from_file (GTK_IMAGE (image), filename); break; } default: break; } gtk_widget_destroy (dialog); }

Toto je trochu komplikovanější než vše, o co jsme se doposud pokusili, takže si to pojďme rozebrat:

Prvním argumentem signálu je vždy widget, který signál vyslal. Někdy za ním může následovat další argument související se signálem, ale clicked žádný nemá. Další je argument user_data, což je ukazatel na data, která předáváme, když signál napojujeme. V tomto případě je to náš objekt GtkImage.

Následující řádek, který stojí za pozornost, je ten, kde je pomocí gtk_file_chooser_dialog_new vytvořeno dialogové okno pro výběr souboru. Funkce přebírá název dialogového okna, rodičovské okno a několik voleb, jako je počet tlačítek a jim příslušející hodnoty.

Všimněte si, že používáme standardní názvy tlačítek z Gtk, místo abychom ručně psali „Cancel“ nebo „Open“. Výhodou použití standardních názvů je, že popisky tlačítek budou vždy přeloženy do uživatelova jazyka.

Následující dva řádky omezí dialogové okno Open, aby zobrazovalo jen soubory, které lze otevřít pomocí GtkImage. Nejprve je vytvořen filtr a pak do něj přidáme všechny druhy souborů podporované v GdkPixbuf (což zahrnuje většinu obrázkových formátů, včetně PNG a JPEG). Nakonec tento filtr nastavíme aby byl filtrem dialogového okna Open.

gtk_dialog_run zobrazí dialogové okno Otevření. To bude čekat, až si uživatel vybere obrázek. Když to udělá, gtk_dialog_run vrátí hodnotu GTK_RESPONSE_ACCEPT (nebo by mohl vrátit GTK_RESPONSE_CANCEL, když uživatel klikne na Zrušit). V bloku switch se to otestuje.

Při předpokladu, že uživatel klikl na Open, následující řádek nastaví vlastnost file u GtkImage na název souboru s obrázkem, který uživatel vybral. GtkImage pak obrázek načte a zobrazí.

Na posledním řádku této metody zlikvidujeme dialogové okno Otevření, protože už jej nebudeme potřebovat. Tím se dialogové okno automaticky skryje.

Sestavení a spuštění aplikace

Celý kód by nyní měl být připravený k fungování. Klikněte na Sestavit Sestavit projekt, aby se vše znovu sestavilo a pak na Spustit Spustit, aby se aplikace spustila.

Pokud jste tak ještě neučinili, zvolte aplikaci Debug/src/image-viewer v dialogovém okně, které se objeví. Nakonec klikněte na Spustit a užijte si ji!

Ukázková implementace

Pokud v této lekci narazíte na nějaké problémy, porovnejte si svůj kód s tímto ukázkovým kódem.

Další postup

Zde je pár nápadů, jak byste mohli tuto jednoduchou ukázku rozšířit:

Umožnit uživateli výběr složky místo souboru a poskytnout ovládání pro procházení všech obrázků v této složce.

Použít při načtení obrázku náhodné filtry a efekty a umožnit uživateli takto změněný obrázek uložit.

GEGL poskytuje mocné schopnosti pro práci s obrázky.

Umožnit uživateli načíst obrázky ze síťového sdílení, skenerů a dalších složitějších zdrojů.

Pro práci se síťovými přenosy můžete použít GIO a pro obsluhu skeneru GNOME Scan.