<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:e="http://projectmallard.org/experimental/" type="guide" style="task" id="model-view-controller.py" xml:lang="cs">

<info>
    <title type="text">Návrh typu Model/Zobrazení/Ovládání (Python)</title>
  <link type="guide" xref="beginner.py#theory"/>
  <link type="next" xref="combobox_multicolumn.py"/>
  <revision version="0.1" date="2012-06-30" status="stub"/>

  <desc>Návrh typu Model/Zobrazení/Ovládání</desc>
  <credit type="author copyright">
    <name>Sebastian Pölsterl</name>
    <email its:translate="no">sebp@k-d-w.org</email>
    <years>2011</years>
  </credit>
  <credit type="author copyright editor">
    <name>Marta Maria Casetti</name>
    <email its:translate="no">mmcasetti@gmail.com</email>
    <years>2012</years>
  </credit>
</info>

<title>Návrh typu Model/Zobrazení/Ovládání</title>

<links type="section"/>

<section id="overview">
<title>Přehled</title>

<p>Widgety <link xref="treeview_simple_liststore.py">TreeView</link> i <link xref="combobox.py">ComboBox</link> jsou postaveny na návrhu <em>Model/Zobrazení/Ovládání</em>. <em>Model</em> (implementace <code>Gtk.TreeModel</code>, obvykle <code>Gtk.TreeStore</code> nebo <code>Gtk.ListStore</code>) uchovává data, <code>Zobrazení</code> (např. <code>Gtk.TreeView</code>, <code>Gtk.ComboBox</code> nebo <code>Gtk.ComboBoxText</code>) přijímá upozornění a zobrazuje obsah modelu. A konečně <code>Ovládání</code> mění stav modelu (přes některé metody, které model implementuje, jako je <code>append()</code> nebo <code>remove()</code>) a upozorňuje zobrazení na tyto změny (pomocí signálu, jako je <code>"changed"</code>).</p>

</section>

<section id="model">
<title>Model</title>

<p>Hlavní rozdíl mezi dvěma hlavními implementacemi <code>Gtk.TreeModel</code> je, že <code>Gtk.ListStore</code> obsahuje jednoduché řádky dat bez potomků, zatímco <code>Gtk.TreeStore</code> obsahuje sice také řádky dat, ale každý řádek může mít synovské řádky (a ty také mohou mít synovské řádky a tak dále).</p>

<p>Data v modelu mohou být získána nebo změněna pomocí stromového iterátoru a sloupcového indexu nebo metody <code>Gtk.TreeIter</code> nebo <code>Gtk.TreePath</code>.</p>

<p>Stejně jako u objektů typu seznam vestavěných v jazyce Python, můžete použít <code>len()</code> k získání počtu řádků a „slice“ (řez) k získání nebo nastavení hodnot. Jinak metoda <code>append()</code> vrací instanci <code>Gtk.TreeIter</code>, která ukazuje na místo, kam byl nový řádek vložen. <code>Gtk.TreeIter</code> můžete získat i zavoláním <code>get_iter()</code>.</p>

<p>Protože <code>Gtk.ListStore</code> obsahuje jen jednu úroveň, tj. uzly nemají žádné potomky, je cesta v podstatě jen index řádku, ke kterému chcete přístup. V případě <code>Gtk.TreeStore</code> je cesta seznam indexů nebo řetězec. Forma řetězce je seznam čísel oddělených dvojtečkami. Každé číslo odkazuje na pořadí v dané úrovni. Takže cesta <code>"0"</code> odkazuje na kořenový uzel a cesta <code>"2:4"</code> odkazuje na pátého potomka třetího uzlu.</p>

<p>Užitečné metody pro <code>Gtk.TreeModel</code>:</p>
<list>
  <item><p><code>get_iter(cesta)</code> vrací instanci <code>Gtk.TreeIter</code> ukazující na <code>cestu</code>. Ta je očekávána v podobě seznamu čísel oddělovaného dvojtečkou nebo n-tice. Například řetězec <code>"10:4:0"</code> je stejná cesta jako n-tice <code>(10, 4, 0)</code>, protože obojí vytvoří cestu do hloubky 3. úrovně k 11. potomku od kořene, 5. pátému potomku jedenáctého potomka a 1. potomku pátého potomka.</p></item>
  <item><p><code>iter_next(stromový_iterátor)</code> vrací instanci <code>Gtk.TreeIter</code> ukazující na uzel následující za <code>stromovým_iterátorem</code> v aktuální úrovni nebo <code>None</code>, pokud tam již další není.</p></item>
  <item><p><code>iter_has_child(stromový_iterátor)</code> vrací <code>True</code> jestliže má <code>stromový_iterátor</code> potomky, jinak <code>False</code>.</p></item>
  <item><p><code>iter_children(stromový_iterátor)</code> vrací instanci <code>Gtk.TreeIter</code> ukazující na prvního potomka <code>stromového_iterátoru</code> nebo <code>None</code>, když žádného potomka nemá.</p></item>
  <item><p><code>get_iter_first()</code> vrací instanci <code>Gtk.TreeIter</code>, která ukazuje na první iterátor ve stromu (tj. na cestě <code>"0"</code>) nebo <code>None</code>, pokud je strom prázdný.</p></item>
</list>

<p>Užitečné metody pro <code>Gtk.ListStore</code>:</p>
<list>
  <item><p><code>append(řádek)</code> připojí nový řádek do <code>ListStore</code>, kde <code>řádek</code> může být seznam hodnot pro každý ze sloupců nebo může být <code>řádek</code> vynechán či <code>None</code> a pak bude připojen prázdný řádek. Tato metoda vrací <code>Gtk.TreeIter</code> ukazující na připojený řádek.</p></item>
  <item><p><code>remove(iterátor)</code> odstraní <code>iterátor</code> z <code>Gtk.ListStore</code> a vrátí <code>True</code> jestliže je iterátor platný nebo <code>False</code> jestliže není. Po odstranění je <code>iterátor</code> nastaven na následující platný řádek.</p></item>
</list>

<p>Užitečné metody pro <code>Gtk.TreeStore</code>:</p>
<list>
  <item><p><code>append(rodič, řádek)</code> přidá do stromového úložiště nový řádek. Argument <code>rodič</code> musí být platný <code>Gtk.TreeIter</code>. Když rodič není <code>None</code>, bude nový řádek přidán za posledního potomka rodiče, jinak bude přidán do nejvyšší úrovně. Argument <code>řádek</code> může být seznam hodnot pro jednotlivé sloupce nebo může být vynechán nebo <code>None</code>. V posledních dvou zmíněných případech bude připojen prázdný řádek. Metoda vrací <code>Gtk.TreeIter</code> ukazující na připojený řádek.</p></item>
  <item><p><code>remove(iterátor)</code> odstraní <code>iterátor</code> z <code>Gtk.ListStore</code> a vrátí <code>True</code> jestliže je iterátor platný nebo <code>False</code> jestliže není. Po odstranění je <code>iterátor</code> nastaven na následující platný řádek.</p></item>
</list>

</section>

<section id="treeview">
<title>Zobrazení: případ TreeView</title>

<p><code>TreeView</code> zobrazuje strukturu dceřiných a rodičovských položek v podobě stromu. Viz třeba <link xref="treeview_treestore.py">tento příklad</link>.</p>

<p><code>Gtk.TreeViewColumn</code> je použito k uspořádání svislých sloupců.</p>

<p>Užitečné metody pro <code>Gtk.TreeView</code>:</p>
<list>
  <item><p><code>set_model(model)</code> nastaví model pro toto stromové zobrazení. Pokud již nějaký model nastavené má, tak ten bude nejdříve odebrán. Jestliže je model <code>None</code>, tak se zruší nastavení starého modelu.</p></item>
  <item><p><code>get_model()</code> vrací model, na kterém je strom založen, <code>None</code>, když model není nastaven.</p></item>
  <item><p><code>append_column(sloupec)</code> připojí <code>sloupec</code> do seznamu sloupců.</p></item>
  <item><p><code>get_selection()</code> vrací <code>Gtk.TreeSelection</code> přidružené k tomuto stromovému zobrazení.</p></item>
</list>

<p>Užitečné metody pro <code>Gtk.TreeViewColumn</code>:</p>
<list>
  <item><p><code>add_attribute(vykreslovač, atribut, hodnota)</code> přidá mapování atributu na tento sloupec. <code>atribut</code> je parametr <code>vykreslovače</code>, který má být nastaven na <code>hodnotu</code>.</p></item>
  <item><p><code>pack_start(vykreslovač, roztáhnout)</code> zabalí <code>vykreslovač</code> do začátku tohoto sloupce. Když je <code>roztáhnout</code> nastaveno na <code>False</code>, nebude si <code>vykreslovač</code> nárokovat víc místa, než potřebuje. Veškeré nevyužité místo je rovnoměrně rozděleno mezi buňky, kterém mají tento parametr nastavený na <code>True</code>.</p></item>
  <item><p><code>pack_end(vykreslovač, roztáhnout)</code> zabalí <code>vykreslovač</code> do konce tohoto sloupce. Když je <code>roztáhnout</code> nastaveno na <code>False</code>, nebude si <code>vykreslovač</code> nárokovat víc místa, než potřebuje. Veškeré nevyužité místo je rovnoměrně rozděleno mezi buňky, kterém mají tento parametr nastavený na <code>True</code>.</p></item>
  <item><p><code>set_sort_column_id(id_slupce_řazení)</code> nastaví sloupec z modelu, podle kterého by se měl tento sloupec (v zobrazení) řadit. Rovněž to zpřístupní záhlaví sloupce pro kliknutí.</p></item>
  <item><p><code>set_sort_indicator(nastavení)</code> nastaví, jestli se má v záhlaví sloupce zobrazovat malá šipka. Argument <code>nastavení</code> může být <code>True</code> (indikátor je zobrazen) nebo <code>False</code>.</p></item>
  <item><p><code>set_sort_order(pořadí)</code> změní pořadí, ve kterém je sloupec seřazen. <code>pořadí</code> může být <code>Gtk.SortType.ASCENDING</code> (vzestupné) nebo <code>Gtk.SortType.DESCENDING</code> (sestupné).</p></item>
</list>

</section>

<section id="combobox">
<title>Zobrazení: případ ComboBox</title>

<p><code>Gtk.ComboBox</code> poskytuje výběr z položek v rozbalovací nabídce, viz třeba <link xref="combobox.py">tento příklad</link>. Pro seznam s čistě textovými položkami lze použít také jednodušší <code>Gtk.ComboBoxText</code>. Obě verze mohou obsahovat vstupní pole.</p>

<p>Užitečné metody pro <code>Gtk.ComboBox</code>:</p>
<list>
  <item><p>Statická metoda <code>new_with_entry()</code> vytvoří nový prázdný <code>Gtk.ComboBox</code> se vstupním polem. Statická metoda <code>new_with_model(model)</code> jej vytvoří s modelem inicializovaným na <code>model</code>. A statická metodat <code>new_with_model_and_entry(model)</code> je kombinací dvou předchozích.</p></item>
  <item><p><code>get_active_iter()</code> vrací <code>Gtk.TreeIter</code> ukazující na právě aktivní položku. Pokud žádná aktivní položka neexistuje, je vráceno <code>None</code>.</p></item>
  <item><p><code>set_model(model)</code> nastaví model použitý tímto rozbalovacím seznamem na <code>model</code> a zruší nastavení předchozího nastaveného modelu (pokud nějaký byl). Pokud je <code>model</code> <code>None</code>, bude jen zrušeno nastavení předchozího. Upozorňujeme, že tato funkce nemaže vykreslovače buněk.</p></item>
  <item><p><code>set_entry_text_column(textový_sloupec)</code> nastavuje sloupec modelu, který by měl tento rozbalovací seznam použít k získávání řetězců, na <code>textový_sloupec</code>. Tento sloupec musí být typu <code>str</code> (to platí v případě, že rozbalovací seznam byl vytvořen s vlastností <code>"has-entry"</code> nastavenou na <code>True</code>).</p></item>
  <item><p><code>set_wrap_width(šířka)</code> nastavuje šířku zalamování rozbalovacího seznamu na <code>šířka</code>. Jedná se v zásadě o upřednostňovaný počet sloupců, když chcete, aby byl rozbalený seznam rozvržen do mřížky.</p></item>
</list>

<p>Užitečné metody pro <code>Gtk.ComboBoxText</code>:</p>
<list>
  <item><p>Statická metoda <code>new_with_entry()</code> vytvoří nový prázdný <code>Gtk.ComboBoxText</code> se vstupním polem.</p></item>
  <item><p><code>append_text(text)</code> připojí <code>text</code> do seznamu řetězců uchovaných v tomto rozbalovacím seznamu.</p></item>
  <item><p><code>get_active_text()</code> vrací aktuálně aktivní řetězec v rozbalovacím seznamu nebo <code>None</code>, když není nic vybráno. V případě, kdy má rozbalovací seznam vstupní pole, vrací tato funkce obsah tohoto pole (což nutně nemusí být žádná položka ze seznamu).</p></item>
</list>

</section>

<section id="cellrenderer">
<title>Zobrazení: vykreslování buněk</title>

<p>K vykreslení různých typů dat používá <code>View</code> objekty <code>Gtk.CellRenderer</code>.</p>

<p>Implementace <code>Gtk.CellRenderer</code> a užitečných metod:</p>
<list>
  <item><p><code>Gtk.CellRendererText</code> – vykresluje text v buňce.</p></item>
  <item><p><code>Gtk.CellRendererToggle</code> – vykresluje v buňce přepínací tlačítko nebo skupinový přepínač. Užitečné metody:</p>
    <list>
    <item><p><code>set_active(nastavení)</code> – aktivuje nebo deaktivuje vykreslování buňky</p></item>
    <item><p><code>get_active()</code> – vrací, jestli je vykreslování buňky aktivní</p></item>
    <item><p><code>set_radio(skupinový_přepínač)</code> – pokud je <code>skupinový_přepínač</code> <code>True</code>, bude vykreslovač buňky vykreslovat skupinový přepínač (tj. navzájem se vylučující přepínače), pokud je <code>False</code>, bude se vykreslovat zaškrtávací políčko (samostatná volba)</p></item>
    <item><p><code>get_radio()</code> – vrací, jestli vykreslujeme skupinové přepínače místo zaškrtávacích políček.</p></item>
    </list>
  </item>
  <item><p><code>Gtk.CellRendererPixbuf</code> – vykresluje obrázek v buňce</p></item>
  <item><p><code>Gtk.CellRendererCombo</code>  – vykresluje v buňce text; ale zatímco <code>Gtk.CellRendererText</code> poskytuje jednoduché vstupní pole pro úpravu textu, <code>Gtk.CellRendererCombo</code> poskytuje pro úpravu textu widget <code>Gtk.ComboBox</code>. Ten lze použít s nebo bez přidruženého widgetu <code>Gtk.Entry</code>, v závislosti na vlastnosti <code>"has-entry"</code>.</p></item>
  <item><p><code>Gtk.CellRendererProgress</code> – vykresluje v buňce číselnou hodnotu v podobě ukazatele průběhu; nad ukazatelem může zobrazit text</p></item>
  <item><p><code>Gtk.CellRendererSpinner</code> – vykresluje v buňce animovanou káču</p></item>
  <item><p><code>Gtk.CellRendererSpin</code> – vykresluje v buňce číselník</p></item>
  <item><p><code>Gtk.CellRendererAccel</code> – vykresluje v buňce klávesovou zkratku</p></item>
</list>

</section>

<section id="selection">
<title>Ovládání: výběr</title>

<p>Většina aplikací potřebuje používat nejen zobrazení dat, ale i přijímat vstupní události od uživatelů. To udělají jednoduše tak, že získají odkaz na objekt s výběrem a napojí se na signál <code>"changed"</code>.</p>

<code mime="text/x-python">
select = tree.get_selection()
select.connect("changed", on_tree_selection_changed)
</code>

<p>Pak k získání dat pro vybraný řádek:</p>

<code mime="text/x-python">
def on_tree_selection_changed(selection):
    model, treeiter = selection.get_selected()
    if treeiter != None:
        print "You selected", model[treeiter][0]
</code>

<p>Užitečné metody pro <code>Gtk.TreeSelection</code>:</p>

<list>
  <item><p><code>set_mode(typ)</code> nastaví typ výběru, kde typ může být něco z</p>
  <list>
    <item><p><code>Gtk.SelectionMode.NONE</code> – není možný žádný výběr</p></item>
    <item><p><code>Gtk.SelectionMode.SINGLE</code> – může být vybrán žádný nebo jeden prvek</p></item>
    <item><p><code>Gtk.SelectionMode.BROWSE</code> – je vybrán právě jeden prvek. V některých případech, jako na počátku nebo v průběhu vyhledávání, je možné, aby nebyl vybrán žádný prvek. To, co je opravdu vynucováno, je, že uživatel nemůže zrušit výběr aktuálně vybraného prvku, jedině může vybrat jiný.</p></item>
    <item><p><code>Gtk.SelectionMode.MULTIPLE</code> – může být vybrán libovolný počet prvků. Kliknutí přepne stav položky. Klávesu <key>Ctrl</key> lze používat k přidávání výběru a klávesu <key>Shift</key> k výběru rozsahu mezi zaměřenou a kliknutou položkou. Některé widgety mohou umožňovat výběr rozsahu prvků i postupem „klikni a táhni“.</p></item>
  </list>
  </item>
  <item><p><code>get_selected()</code> vrací dvojici <code>(model, stromový_iterátor)</code>, kde <code>model</code> je aktuální model a <code>stromový_iterátor</code> je <code>Gtk.TreeIter</code> ukazující na aktuálně vybraný řádek nebo <code>None</code>, když není žádný řádek vybrán. Metoda nepracuje, když je režim výběru nastaven na <code>Gtk.SelectionMode.MULTIPLE</code>. V tomto případě použijte místo toho <code>get_selected_rows()</code>, která vrací seznam instancí <code>Gtk.TreePath</code> se všemi vybranými řádky.</p></item>
</list>

</section>

<section id="references">
<title>Odkazy</title>

<list>
  <item><p><link href="http://developer.gnome.org/gtk3/unstable/GtkTreeModel.html">GtkTreeModel</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/unstable/GtkTreeView.html">GtkTreeView</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/unstable/GtkTreeViewColumn.html">GtkTreeViewColumn</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/unstable/GtkComboBox.html">GtkComboBox</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/unstable/GtkCellRenderer.html">GtkCellRenderer</link></p></item>
</list>

</section>

</page>
