Prohlížeč obrázků (Vala) 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 Philip Chimento philip.chimento@gmail.com Tiffany Antopolski tiffany.antopolski@gmail.com Marta Maria Casetti mmcasetti@gmail.com 2013 Prohlížeč obrázků

V této lekci vytvoříte aplikaci, která otevře a zobrazí soubor s obrázkem. Naučíte se:

Jak vytvořit základní projekt pomocí IDE Anjuta.

Jak napsat aplikaci Gtk v jazyce Vala.

Některé základní koncepty programování s GObject

Abyste mohli pokračovat v této lekci, budete potřebovat následující:

Základní znalosti programovacího jazyka Vala.

Nainstalovanou kopii vývojářského studia Anjuta.

Může se vám hodit referenční příručka k API gtk+-3.0, ačkoliv pro tuto výuku není nutná.

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 aplikaci Anjuta a klikněte na Vytvořit nový projekt nebo Soubor Nový Projekt, aby se otevřel průvodce projektem.

Na kartě Vala 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ě.

Jak používat builder k tvorbě rozhraní se můžete naučit v lekci Kytarová ladička.

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

using GLib; using Gtk; public class Main : Object { public Main () { Window window = new Window(); window.set_title ("Hello World"); window.show_all(); window.destroy.connect(on_destroy); } public void on_destroy (Widget window) { Gtk.main_quit(); } static int main (string[] args) { Gtk.init (ref args); var app = new Main (); Gtk.main (); return 0; } }
Prvotní sestavení kódu

Kód načte (prázdné) okno ze souboru s popisem uživatelského rozhraní a zobrazí jej. Dále to podrobněji rozebereme. Pokud jste již pochopili základy, tak tento seznam můžete přeskočit:

Dva řádky using v horní části naimportují jmenné prostory, abychom je nemuseli výslovně uvádět.

Konstruktor třídy Main vytvoří nové (prázdné) okno a napojí signál, aby se aplikace ukončila, když se zavře 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 static main se spustí jako výchozí, když spustíte aplikaci napsanou v jazyce Vala. Volá pár funkcí, které vytvoří třídu Main a 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).

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).

Změňte Konfiguraci na Výchozí a klikněte na Spustit, aby se nakonfigurovala složka, ve které se provádí 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ů Gtk.Container, které mohou obsahovat další widgety i další kontejnery. Zde použijeme nejjednodušší dostupný kontejner Gtk.Box.

Přidejte následující řádky na začátek třídy Main:

private Window window; private Image image;

Nyní nahraďte současný konstruktor tímto uvedeným níže:

public Main () { window = new Window (); window.set_title ("Image Viewer in Vala"); // Nastaví uživatelské rozhraní var box = new Box (Orientation.VERTICAL, 5); var button = new Button.with_label ("Open image"); image = new Image (); box.pack_start (image, true, true, 0); box.pack_start (button, false, false, 0); window.add (box); // Zobrazí dialogové okno při otevírání souboru button.clicked.connect (on_open_image); window.show_all (); window.destroy.connect (main_quit); }

První dva řádky jsou částí GUI a budeme k nim potřebovat přístup z více než jedné metody. Proto je deklarujeme zde, takže budou přístupné skrze třídu. Jinak by byly přístupné jen v metodě, kde by byly vytvořeny.

První řádek konstruktoru vytvoří prázdné okno. Následující řádky vytvoří widgety, které chceme používat: tlačítko pro otevření obrázku, vlastní widget pro zobrazení obrázku a box sloužící jako kontejner.

Volání 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 jsem 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 button, vyšle se signál clicked, který může být napojen na nějakou akci (definovanou v metodě zpětného volání).

To se udělá pomocí metody connect signálu clicked u tlačítka, což v tomto případě řekne GTK, aby ve chvíli, kdy je na tlačítko kliknuto, zavolalo (zatím nenadefinovanou) metodu zpětného volání on_image_open. Zpětné volání nadefinujeme v další části.

Ve zpětném volání potřebujeme přístup k widgetům window a image, což je důvod, proč je definujeme jako soukromé členy na začátku naší třídy.

Poslední volání funkce connect zajistí, že se aplikace ukončí, když je zavřeno okno. Kód, který vygenerovala Anjuta, volá metodu zpětného volání on_destroy, která volá Gtk.main_quit, ale prosté napojení signálu na main_quit je jednodušší. Metodu on_destroy můžete smazat.

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 za konstruktor:

public void on_open_image (Button self) { var filter = new FileFilter (); var dialog = new FileChooserDialog ("Open image", window, FileChooserAction.OPEN, Stock.OK, ResponseType.ACCEPT, Stock.CANCEL, ResponseType.CANCEL); filter.add_pixbuf_formats (); dialog.add_filter (filter); switch (dialog.run ()) { case ResponseType.ACCEPT: var filename = dialog.get_filename (); image.set_from_file (filename); break; default: break; } dialog.destroy (); }

Toto je trochu složitější, takže si to pojďme rozebrat:

Obsluha signálu je typ metody zpětného volání, která je volána, když je vyslán signál. Běžně se k označní používají oba termíny.

Prvním argumentem metody zpětného volání 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á.

V tomto případě button vyšle signál clicked, který je napojen na metodu zpětného volání on_open_image:

button.clicked.connect (on_open_image);

Metoda on_open_image přebírá jako argument tlačítko, které vyslalo signál:

public void on_open_image (Button self)

Dalším zajímavým řádkem je ten, kde je vytvořeno dialogové okno pro výběr souboru. Konstruktor widgetu FileChooserDialog přebírá název do záhlaví dialogového okna, rodičovské okno a několik voleb, jako je počet tlačítek a jim odpovídají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.

dialog.run zobrazí dialogové okno Open. Dialogové okno bude čekat na uživatele, než si vybere obrázek. Až tak učiní, vrátí dialog.run hodnotu ResponseType.ACCEPT typu ResponseType nebo by mohl vrátit ResponseType.CANCEL, když uživatel klikne na Cancel. Otestujeme to výrazem switch.

Při předpokladu, že uživatel klikl na Open, následující řádek získá název souboru s obrázkem, který uživatel vybral a řekne widgetu GtkImage, aby jej načetl a zobrazil.

Na posledním řádku této metody zlikvidujeme dialogové okno Open, protože jej již nebudeme potřebovat.

Zlikvidování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 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:

Nastavit ji tak, že když se okno otevře, bude mít konkrétní počáteční velikost. Například 200 × 200 pixelů.

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.