# Návrh typu Model/Zobrazení/Ovládání (Python)

Návrh typu Model/Zobrazení/Ovládání
Sebastian Pölsterl
sebp@k-d-w.org 2011
Marta Maria Casetti
mmcasetti@gmail.com 2012

# Návrh typu Model/Zobrazení/Ovládání

# Přehled

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

# Model

Hlavní rozdíl mezi dvěma hlavními implementacemi `Gtk.TreeModel` je, že `Gtk.ListStore` obsahuje jednoduché řádky dat bez potomků, zatímco `Gtk.TreeStore` 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).

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

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

Protože `Gtk.ListStore` 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ě `Gtk.TreeStore` 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 `"0"` odkazuje na kořenový uzel a cesta `"2:4"` odkazuje na pátého potomka třetího uzlu.

Užitečné metody pro `Gtk.TreeModel`:

`get_iter(cesta)` vrací instanci `Gtk.TreeIter` ukazující na `cestu`. Ta je očekávána v podobě seznamu čísel oddělovaného dvojtečkou nebo n-tice. Například řetězec `"10:4:0"` je stejná cesta jako n-tice `(10, 4, 0)`, 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.

`iter_next(stromový_iterátor)` vrací instanci `Gtk.TreeIter` ukazující na uzel následující za `stromovým_iterátorem` v aktuální úrovni nebo `None`, pokud tam již další není.

`iter_has_child(stromový_iterátor)` vrací `True` jestliže má `stromový_iterátor` potomky, jinak `False`.

`iter_children(stromový_iterátor)` vrací instanci `Gtk.TreeIter` ukazující na prvního potomka `stromového_iterátoru` nebo `None`, když žádného potomka nemá.

`get_iter_first()` vrací instanci `Gtk.TreeIter`, která ukazuje na první iterátor ve stromu (tj. na cestě `"0"`) nebo `None`, pokud je strom prázdný.

Užitečné metody pro `Gtk.ListStore`:

`append(řádek)` připojí nový řádek do `ListStore`, kde `řádek` může být seznam hodnot pro každý ze sloupců nebo může být `řádek` vynechán či `None` a pak bude připojen prázdný řádek. Tato metoda vrací `Gtk.TreeIter` ukazující na připojený řádek.

`remove(iterátor)` odstraní `iterátor` z `Gtk.ListStore` a vrátí `True` jestliže je iterátor platný nebo `False` jestliže není. Po odstranění je `iterátor` nastaven na následující platný řádek.

Užitečné metody pro `Gtk.TreeStore`:

`append(rodič, řádek)` přidá do stromového úložiště nový řádek. Argument `rodič` musí být platný `Gtk.TreeIter`. Když rodič není `None`, bude nový řádek přidán za posledního potomka rodiče, jinak bude přidán do nejvyšší úrovně. Argument `řádek` může být seznam hodnot pro jednotlivé sloupce nebo může být vynechán nebo `None`. V posledních dvou zmíněných případech bude připojen prázdný řádek. Metoda vrací `Gtk.TreeIter` ukazující na připojený řádek.

`remove(iterátor)` odstraní `iterátor` z `Gtk.ListStore` a vrátí `True` jestliže je iterátor platný nebo `False` jestliže není. Po odstranění je `iterátor` nastaven na následující platný řádek.

# Zobrazení: případ TreeView

`TreeView` zobrazuje strukturu dceřiných a rodičovských položek v podobě stromu. Viz třeba tento příklad.

`Gtk.TreeViewColumn` je použito k uspořádání svislých sloupců.

Užitečné metody pro `Gtk.TreeView`:

`set_model(model)` nastaví model pro toto stromové zobrazení. Pokud již nějaký model nastavené má, tak ten bude nejdříve odebrán. Jestliže je model `None`, tak se zruší nastavení starého modelu.

`get_model()` vrací model, na kterém je strom založen, `None`, když model není nastaven.

`append_column(sloupec)` připojí `sloupec` do seznamu sloupců.

`get_selection()` vrací `Gtk.TreeSelection` přidružené k tomuto stromovému zobrazení.

Užitečné metody pro `Gtk.TreeViewColumn`:

`add_attribute(vykreslovač, atribut, hodnota)` přidá mapování atributu na tento sloupec. `atribut` je parametr `vykreslovače`, který má být nastaven na `hodnotu`.

`pack_start(vykreslovač, roztáhnout)` zabalí `vykreslovač` do začátku tohoto sloupce. Když je `roztáhnout` nastaveno na `False`, nebude si `vykreslovač` 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 `True`.

`pack_end(vykreslovač, roztáhnout)` zabalí `vykreslovač` do konce tohoto sloupce. Když je `roztáhnout` nastaveno na `False`, nebude si `vykreslovač` 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 `True`.

`set_sort_column_id(id_slupce_řazení)` 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í.

`set_sort_indicator(nastavení)` nastaví, jestli se má v záhlaví sloupce zobrazovat malá šipka. Argument `nastavení` může být `True` (indikátor je zobrazen) nebo `False`.

`set_sort_order(pořadí)` změní pořadí, ve kterém je sloupec seřazen. `pořadí` může být `Gtk.SortType.ASCENDING` (vzestupné) nebo `Gtk.SortType.DESCENDING` (sestupné).

# Zobrazení: případ ComboBox

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

Užitečné metody pro `Gtk.ComboBox`:

Statická metoda `new_with_entry()` vytvoří nový prázdný `Gtk.ComboBox` se vstupním polem. Statická metoda `new_with_model(model)` jej vytvoří s modelem inicializovaným na `model`. A statická metodat `new_with_model_and_entry(model)` je kombinací dvou předchozích.

`get_active_iter()` vrací `Gtk.TreeIter` ukazující na právě aktivní položku. Pokud žádná aktivní položka neexistuje, je vráceno `None`.

`set_model(model)` nastaví model použitý tímto rozbalovacím seznamem na `model` a zruší nastavení předchozího nastaveného modelu (pokud nějaký byl). Pokud je `model` `None`, bude jen zrušeno nastavení předchozího. Upozorňujeme, že tato funkce nemaže vykreslovače buněk.

`set_entry_text_column(textový_sloupec)` nastavuje sloupec modelu, který by měl tento rozbalovací seznam použít k získávání řetězců, na `textový_sloupec`. Tento sloupec musí být typu `str` (to platí v případě, že rozbalovací seznam byl vytvořen s vlastností `"has-entry"` nastavenou na `True`).

`set_wrap_width(šířka)` nastavuje šířku zalamování rozbalovacího seznamu na `šířka`. Jedná se v zásadě o upřednostňovaný počet sloupců, když chcete, aby byl rozbalený seznam rozvržen do mřížky.

Užitečné metody pro `Gtk.ComboBoxText`:

Statická metoda `new_with_entry()` vytvoří nový prázdný `Gtk.ComboBoxText` se vstupním polem.

`append_text(text)` připojí `text` do seznamu řetězců uchovaných v tomto rozbalovacím seznamu.

`get_active_text()` vrací aktuálně aktivní řetězec v rozbalovacím seznamu nebo `None`, 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).

# Zobrazení: vykreslování buněk

K vykreslení různých typů dat používá `View` objekty `Gtk.CellRenderer`.

Implementace `Gtk.CellRenderer` a užitečných metod:

`Gtk.CellRendererText` – vykresluje text v buňce.

`Gtk.CellRendererToggle` – vykresluje v buňce přepínací tlačítko nebo skupinový přepínač. Užitečné metody:

`set_active(nastavení)` – aktivuje nebo deaktivuje vykreslování buňky

`get_active()` – vrací, jestli je vykreslování buňky aktivní

`set_radio(skupinový_přepínač)` – pokud je `skupinový_přepínač` `True`, bude vykreslovač buňky vykreslovat skupinový přepínač (tj. navzájem se vylučující přepínače), pokud je `False`, bude se vykreslovat zaškrtávací políčko (samostatná volba)

`get_radio()` – vrací, jestli vykreslujeme skupinové přepínače místo zaškrtávacích políček.

`Gtk.CellRendererPixbuf` – vykresluje obrázek v buňce

`Gtk.CellRendererCombo` – vykresluje v buňce text; ale zatímco `Gtk.CellRendererText` poskytuje jednoduché vstupní pole pro úpravu textu, `Gtk.CellRendererCombo` poskytuje pro úpravu textu widget `Gtk.ComboBox`. Ten lze použít s nebo bez přidruženého widgetu `Gtk.Entry`, v závislosti na vlastnosti `"has-entry"`.

`Gtk.CellRendererProgress` – vykresluje v buňce číselnou hodnotu v podobě ukazatele průběhu; nad ukazatelem může zobrazit text

`Gtk.CellRendererSpinner` – vykresluje v buňce animovanou káču

`Gtk.CellRendererSpin` – vykresluje v buňce číselník

`Gtk.CellRendererAccel` – vykresluje v buňce klávesovou zkratku

# Ovládání: výběr

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 `"changed"`.

select = tree.get_selection() select.connect("changed", on_tree_selection_changed)

Pak k získání dat pro vybraný řádek:

def on_tree_selection_changed(selection): model, treeiter = selection.get_selected() if treeiter != None: print "You selected", model[treeiter][0]

Užitečné metody pro `Gtk.TreeSelection`:

`set_mode(typ)` nastaví typ výběru, kde typ může být něco z

`Gtk.SelectionMode.NONE` – není možný žádný výběr

`Gtk.SelectionMode.SINGLE` – může být vybrán žádný nebo jeden prvek

`Gtk.SelectionMode.BROWSE` – 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ý.

`Gtk.SelectionMode.MULTIPLE` – může být vybrán libovolný počet prvků. Kliknutí přepne stav položky. Klávesu Ctrl lze používat k přidávání výběru a klávesu Shift 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“.

`get_selected()` vrací dvojici `(model, stromový_iterátor)`, kde `model` je aktuální model a `stromový_iterátor` je `Gtk.TreeIter` ukazující na aktuálně vybraný řádek nebo `None`, když není žádný řádek vybrán. Metoda nepracuje, když je režim výběru nastaven na `Gtk.SelectionMode.MULTIPLE`. V tomto případě použijte místo toho `get_selected_rows()`, která vrací seznam instancí `Gtk.TreePath` se všemi vybranými řádky.

# Odkazy

GtkTreeModel

GtkTreeView

GtkTreeViewColumn

GtkComboBox

GtkCellRenderer