|
Packit |
1470ea |
|
|
Packit |
1470ea |
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.py" xml:lang="cs">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<title type="text">Prohlížeč obrázků (Python)</title>
|
|
Packit |
1470ea |
<link type="guide" xref="py#examples"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>O trošku složitější aplikace než jednoduché „Hello world“ – napíšeme prohlížeč obrázku v GTK.</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<revision pkgversion="0.1" version="0.1" date="2011-03-19" status="review"/>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Jonh Wendell</name>
|
|
Packit |
1470ea |
<email its:translate="no">jwendell@gnome.org</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Johannes Schmid</name>
|
|
Packit |
1470ea |
<email its:translate="no">jhs@gnome.org</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="editor">
|
|
Packit |
1470ea |
<name>Marta Maria Casetti</name>
|
|
Packit |
1470ea |
<email its:translate="no">mmcasetti@gmail.com</email>
|
|
Packit |
1470ea |
<years>2013</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>Prohlížeč obrázků</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
V této lekci napíšeme velmi jednoduchou aplikaci GTK, která načítá a zobrazuje soubory s obrázky. Naučíte se tyto věci:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>Psát základní uživatelské rozhraní GTK v jazyce Python </item>
|
|
Packit |
1470ea |
<item>Zacházet s událostmi pomocí připojení signálu na obsluhu signálu. </item>
|
|
Packit |
1470ea |
<item>Rozvrhnout uživatelské rozhraní GTK pomocí kontejnerů. </item>
|
|
Packit |
1470ea |
<item>Načíst a zobrazit soubor s obrázkem. </item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
Abyste mohli pokračovat v této lekci, budete potřebovat následující:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>Nainstalovanou kopii <link xref="getting-ready">IDE Anjuta</link> </item>
|
|
Packit |
1470ea |
<item>Základní znalosti programovacího jazyka Python </item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<media type="image" mime="image/png" src="media/image-viewer.png"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="anjuta">
|
|
Packit |
1470ea |
<title>Vytvoření projektu ve studiu Anjuta</title>
|
|
Packit |
1470ea |
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ě.
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Spusťte IDE Anjuta a klikněte na <guiseq><gui>Soubor</gui> <gui>Nový</gui> <gui>Projekt</gui></guiseq>, aby se otevřel průvodce projektem.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Na kartě <gui>Python</gui> zvolte <gui>PyGTK (automake)</gui>, klikněte na <gui>Pokračovat</gui> a na několika následujících stránkách vyplňte své údaje. Jako název projektu a složky použijte <file>image-viewer</file>.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Ujistěte se, že <gui>Použít GtkBuilder k tvorbě uživatelského rozhraní</gui> je vypnuto, protože jej chceme v této lekci vytvořit ručně. Na příklad, jak používat návrhář uživatelského rozhraní, se podívejte do lekce <link xref="guitar-tuner.py">Kytarová ladička</link>.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Klikněte na <gui>Použít</gui> a vytvoří se vám projekt. Otevřete <file>src/image_viewer.py</file> na kartě <gui>Projekt</gui> nebo <gui>Soubor</gui>. Obsahuje úplně základní kód příkladu.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="first">
|
|
Packit |
1470ea |
<title>První aplikace Gtk</title>
|
|
Packit |
1470ea |
Pojďme se podívat, jak by úplně základní aplikace Gtk mohl vypadat v jazyce Python:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
from gi.repository import Gtk, GdkPixbuf, Gdk
|
|
Packit |
1470ea |
import os, sys
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
class GUI:
|
|
Packit |
1470ea |
def __init__(self):
|
|
Packit |
1470ea |
window = Gtk.Window()
|
|
Packit |
1470ea |
window.set_title ("Hello World")
|
|
Packit |
1470ea |
window.connect_after('destroy', self.destroy)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
window.show_all()
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def destroy(window, self):
|
|
Packit |
1470ea |
Gtk.main_quit()
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def main():
|
|
Packit |
1470ea |
app = GUI()
|
|
Packit |
1470ea |
Gtk.main()
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
if __name__ == "__main__":
|
|
Packit |
1470ea |
sys.exit(main())
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Podívejme se, co se stane:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
První řádek importuje jmenný prostor Gtk (tzn. vloží knihovnu Gtk). Knihovny jsou poskytovány pomocí GObject Introspection (gi), který poskytuje vazbu jazyka pro řadu knihoven GNOME.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Metoda __init__ třídy GUI vytvoří (prázdné) okno Gtk.Window , nastaví jeho název do záhlaví a napojí signál, aby se aplikace ukončila při zavření okna. Toto je celkem jednoduché a více si o signálech povíme později.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Pak je definována funkce destroy , která akorát ukončí aplikaci. Je volána signálem "destroy" napojeným již dříve.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Zbytek souboru provádí inicializaci pro Gtk a zobrazí GUI.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Tento kód je připravený ke spuštění, takže zkuste použít <guiseq><gui>Spustit</gui> <gui>Spustit</gui></guiseq>. Mělo by se vám zobrazit prázdné okno.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="signals">
|
|
Packit |
1470ea |
<title>Signály</title>
|
|
Packit |
1470ea |
Signály jsou klíčovým konceptem programování v Gtk. Kdykoliv se něco stane u nějakého objektu, tak onen objekt vyšle signál. Například, když je kliknuto na tlačítko, vyšle signál "clicked" . Pokud chcete, aby váš program něco udělal, když tato událost nastane, musíte napojit funkci („obsluhu signálu“) na tento signál. Zde je příklad:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def button_clicked () :
|
|
Packit |
1470ea |
print "you clicked me!"
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
b = new Gtk.Button ("Click me")
|
|
Packit |
1470ea |
b.connect_after ('clicked', button_clicked)
|
|
Packit |
1470ea |
Poslední dva řádky vytvoří Gtk.Button nazvané b a napojí jeho signál clicked na funkci button_clicked , která byla definována dříve. Pokaždé, když je kliknuto na tlačítko, provede se kód ve funkci button_clicked . Ten akorát vypíše zprávu.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="containers">
|
|
Packit |
1470ea |
<title>Kontejnery: Rozvržení uživatelského rozhraní</title>
|
|
Packit |
1470ea |
Widgety (ovládací prvky, jako jsou tlačítka a popisky) lze v okně uspořádat pomocí kontejnerů. Můžete dohromady kombinovat různé kontejnery, jako jsou boxy nebo mřížky.
|
|
Packit |
1470ea |
Gtk.Window je samo o sobě kontejner, ale přímo do něj můžete vložit jen jeden widget. My bychom měli rádi dva widgety, obrázek a tlačítko, takže musíme do okna vložit „vysokokapacitní“ kontejner, pro tyto další widgety. Je dostupná řada <link href="http://library.gnome.org/devel/gtk/stable/GtkContainer.html">typů kontejnerů</link>, ale my zde použijeme Gtk.Box . Ten může obsahovat několik widgetů uspořádaných vodorovně nebo svisle. Složitější rozvržení můžete udělat vložením několika boxů do jiného boxu atd.
|
|
Packit |
1470ea |
<note>
|
|
Packit |
1470ea |
Existuje návrhář grafického uživatelského rozhraní nazývaný <app>Glade</app>, který je zaintegrován i do IDE <app>Anjuta</app>. S ním můžete navrhovat uživatelské rozhraní opravdu snadno. V tomto příkladu ale vše napíšeme ručně.
|
|
Packit |
1470ea |
</note>
|
|
Packit |
1470ea |
Pojďme přidat box a widgety do okna. Vložte následující kód do metody __init__ , hned za řádek window.connect_after :
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
box = Gtk.Box()
|
|
Packit |
1470ea |
box.set_spacing (5)
|
|
Packit |
1470ea |
box.set_orientation (Gtk.Orientation.VERTICAL)
|
|
Packit |
1470ea |
window.add (box)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
První řádek vytvoří Gtk.Box nazvaný box a následující řádky nastaví dvě jeho vlastnosti: orientation (otočení) je nastavena na svislou (takže widgety jsou uspořádány do sloupce) a spacing (rozestupy) mezi widgety jsou nastaveny na 5 pixelů. Následující řádek pak přidá nově vytvořený Gtk.Box do okna.
|
|
Packit |
1470ea |
Zatím okno obsahuje jen prázdný Gtk.Box a pokud spustíte program nyní, neuvidíte oproti dřívějšku žádné změny (Gtk.Box je průhledný kontejner, takže jej tam nemůžete vidět).
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="packing">
|
|
Packit |
1470ea |
<title>Balení: Přidání widgetů do kontejneru</title>
|
|
Packit |
1470ea |
Pro přidání nějakého widgetu do Gtk.Box vložte následující kód hned za řádek window.add (box) :
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
self.image = Gtk.Image()
|
|
Packit |
1470ea |
box.pack_start (self.image, False, False, 0)
|
|
Packit |
1470ea |
První řádek vytvoří nový Gtk.Image nazvaný image , který bude zobrazovat soubor s obrázkem. Protože jej budeme později potřebovat v obsluze signálu, nadefinujeme jej jako proměnou třídy. Musíte přidat image = 0 na začátek třídy GUI . Po té je widget obrázku přidán (zabalen) do kontejneru box pomocí metody <link href="http://library.gnome.org/devel/gtk/stable/GtkBox.html#gtk-box-pack-start">pack_start </link> widgetu GtkBox .
|
|
Packit |
1470ea |
pack_start přebírá 4 argumenty: widget, který je přidáván do Gtk.Box (child ); zda by se měl Gtk.Box zvětšit, když je přidán nový widget (expand ); zda by měl nový widget zabrat všechno vytvořené dodatečné místo, když je Gtk.Box větší (fill ); jak moc místa, v pixelech, by mělo být mezi widgetem a jeho sousedem uvnitř Gtk.Box (padding ).
|
|
Packit |
1470ea |
Kontejnery Gtk (a widgety) se dynamicky roztahují, aby zaplnily dostupné místo, pokud jim to tedy dovolíte. Neumisťujte widgety zadáváním přesných souřadnic x,y v okně. Místo toho je umisťujte relativně vůči sobě. To umožní oknu, které se o ně stará, jednodušeji měnit velikost a widgety by tak měli dostat automaticky rozumnou velikost ve většině situací.
|
|
Packit |
1470ea |
Všimněte si také, jak jsou widgety uspořádány do hierarchie. Jakmile jsou zabaleny v Gtk.Box , je Gtk.Image považován za potomka Gtk.Box. To umožňuje zacházet se všemi potomky widgetu jako se skupinou. Například byste mohli skrýt Gtk.Box , což by zároveň skrylo i všechny jeho potomky.
|
|
Packit |
1470ea |
Nyní vložte tyto dva řádky pod ty dva, které jsme již přidali:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
button = Gtk.Button ("Open a picture...")
|
|
Packit |
1470ea |
box.pack_start (button, False, False, 0)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Tyto řádky jsou podobné jako první dva, ale tentokrát vytváří Gtk.Button a přidávají ho do widgetu box . Všimněte si, že zde nastavujeme argument expand (ten druhý) na False , zatímco pro Gtk.Image byl nastaven na True . To způsobí, že obrázek zabere všechno dostupné místo a tlačítko jen tolik místa, kolik potřebuje. Když okno maximalizujete, zůstane velikost tlačítka stejná, ale obrázek se zvětší, aby zabral celý zbytek okna.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="loading">
|
|
Packit |
1470ea |
<title>Načtení obrázku: Napojení signálu clicked od tlačítka</title>
|
|
Packit |
1470ea |
Když uživatel klikne na tlačítko <gui>Open Image…</gui>, mělo by se objevit dialogové okno, ve kterém si uživatel může vybrat obrázek. Až jej má vybraný, měl by se obrázek načíst a zobrazit ve widgetu obrázku.
|
|
Packit |
1470ea |
Prvním krokem je napojit signál clicked od tlačítka na obslužnou funkci signálu, kterou jsem nazvali on_open_clicked . Vložte tento kód hned za řádek button = Gtk.Button() , kde bylo tlačítko vytvořeno:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
button.connect_after('clicked', self.on_open_clicked)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Tímto se připojí signál clicked k metodě on_open_clicked , která bude definována níže.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="loading2">
|
|
Packit |
1470ea |
<title>Načítání obrázku: Psaní zpětných volání pro signály</title>
|
|
Packit |
1470ea |
Nyní vytvoříme metodu on_open_clicked . Vložte následující do bloku s kódem třídy GUI za metodu __init__ :
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def on_open_clicked (self, button):
|
|
Packit |
1470ea |
dialog = Gtk.FileChooserDialog ("Open Image", button.get_toplevel(), Gtk.FileChooserAction.OPEN);
|
|
Packit |
1470ea |
dialog.add_button (Gtk.STOCK_CANCEL, 0)
|
|
Packit |
1470ea |
dialog.add_button (Gtk.STOCK_OK, 1)
|
|
Packit |
1470ea |
dialog.set_default_response(1)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
filefilter = Gtk.FileFilter ()
|
|
Packit |
1470ea |
filefilter.add_pixbuf_formats ()
|
|
Packit |
1470ea |
dialog.set_filter(filefilter)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
if dialog.run() == 1:
|
|
Packit |
1470ea |
self.image.set_from_file(dialog.get_filename())
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
dialog.destroy()
|
|
Packit |
1470ea |
Toto je trochu komplikovanější než vše, o co jsme se doposud pokusili, takže si to pojďme rozebrat:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Řádek začínající dialog vytvoří dialogové okno <gui>Open</gui>, které může uživatel použít k výběru souboru. Nastavíme tři vlastnosti: název dialogového okna; akci (typ) dialogového okna (jde o dialogové okno <gui>Open</gui>, ale mohli bychom použít SAVE , pokud by záměrem bylo uložení souboru; transient_for , která nastaví rodičovské okno dialogového okna.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Následující dva řádky přidají do dialogového okna tlačítka <gui>Cancel</gui> a <gui>Open</gui>. Druhým argumentem metody add_button je celočíselná hodnota, která bude vrácena při zmáčknutí tlačítka: 0 pro <gui>Cancel</gui> a 1 pro <gui>Open</gui>.
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
set_default_response určuje tlačítko, které bude aktivováno, když uživatel dvojitě klikne na soubor nebo zmáčkne <key>Enter</key>. V našem případě používáme jako výchozí tlačítko <gui>Open</gui> (které má hodnotu 1).
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Následující tři řádky omezí dialogové okno <gui>Open</gui>, aby zobrazovalo jen soubory, které lze otevřít pomocí Gtk.Image . Nejprve je vytvořen filtr a pak do něj přidáme všechny druhy souborů podporované v Gdk.Pixbuf (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 <gui>Open</gui>.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
dialog.run zobrazí dialogové okno <gui>Open</gui>. Dialogové okno bude čekat na uživatele, než si vybere nějaký nějaký obrázek. Až tak učiní, vrátí dialog.run hodnotu <output>1</output> nebo by mohl vrátit <output>0</output>, když uživatel klikne na <gui>Cancel</gui>. Otestujeme to výrazem if .
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>Předpokládejme, že uživatel klikl na <gui>Open</gui>. Následující řádek nastaví vlastnost file v Gtk.Image na název souboru s obrázkem, který si uživatel vybral. Gtk.Image vybraný obrázek načte a zobrazí.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Na posledním řádku této metody zlikvidujeme dialogové okno <gui>Open</gui>, protože jej již nebudeme potřebovat.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="run">
|
|
Packit |
1470ea |
<title>Spuštění aplikace</title>
|
|
Packit |
1470ea |
Všechen kód, který potřebujete, je nyní nachystaný, takže jej můžete zkusit spustit. Tím jste během krátké chvíle získali, co jsme slíbili – plně funkční prohlížeč obrázků (a tím končí naše cesta jazykem Python a knihovnou Gtk).
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="impl">
|
|
Packit |
1470ea |
<title>Ukázková implementace</title>
|
|
Packit |
1470ea |
Pokud v této lekci narazíte na nějaké problémy, porovnejte si svůj kód s tímto <link href="image-viewer/image-viewer.py">ukázkovým kódem</link>.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="next">
|
|
Packit |
1470ea |
<title>Další postup</title>
|
|
Packit |
1470ea |
Zde je pár nápadů, jak byste mohli tuto jednoduchou ukázku rozšířit:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
<link href="http://www.gegl.org/api.html">GEGL</link> poskytuje mocné schopnosti pro práci s obrázky.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Umožnit uživateli načíst obrázky ze síťového sdílení, skenerů a dalších složitějších zdrojů.
|
|
Packit |
1470ea |
Pro práci se síťovými přenosy můžete použít <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> a pro obsluhu skeneru <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link>.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</page>
|