Blame platform-demos/cs/image-viewer.py.page

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>