<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2001/XInclude" type="guide" style="task" id="combobox.js" xml:lang="cs">
  <info>
  <title type="text">ComboBox (JavaScript)</title>
    <link type="guide" xref="beginner.js#menu-combo-toolbar"/>
    <link type="seealso" xref="GtkApplicationWindow.js"/>
    <link type="seealso" xref="comboboxtext.js"/>
    <link type="seealso" xref="messagedialog.js"/>
    <link type="seealso" xref="treeview_simple_liststore.js"/>
    <revision version="0.1" date="2012-07-09" status="draft"/>

    <credit type="author copyright">
      <name>Taryn Fox</name>
      <email its:translate="no">jewelfox@fursona.net</email>
      <years>2012</years>
    </credit>

    <desc>Přizpůsobitelná rozbalovací nabídka</desc>
  </info>

  <title>ComboBox</title>
  <media type="image" mime="image/png" src="media/combobox_multicolumn.png"/>
  <p><code>ComboBox</code> (rozbalovací seznam) je vysoce přizpůsobitelná rozbalovací nabídka. Obsahuje obdobu widgetu <link xref="treeview_simple_liststore.js">TreeView</link>, který se objeví po kliknutí, doplněného modelem <code>ListStore</code> (což je v zásadě tabulka), který udává, co se nachází v řádcích a sloupcích. V tomto příkladu má náš <code>ListStore</code> v jednom sloupci název volby a v druhém název standardní ikony, který je v rozbalovacím seznamu přeměněn na ikonu u každé z voleb.</p>
  <p>Vybíráte celý řádek naráz, takže ikona není oddělenou volbou. Ona a text vedle ní tvoří jednu volbu, na kterou můžete kliknout.</p>
  <note style="tip"><p>Práce s <code>ListStore</code> zabere nějaký čas. Jestli chcete jen jednoduchou čistě textovou rozbalovací nabídku, podívejte se na <link xref="comboboxtext.js">ComboBoxText</link>. Jeho vytvoření nezabere tolik času a jednodušeji se s ním pracuje.</p></note>
    <links type="section"/>

  <section id="imports">
    <title>Importované knihovny</title>
    <code mime="application/javascript">
#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';

const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
</code>
    <p>Toto jsou knihovny, které potřebujeme naimportovat, aby aplikace běžela. Pamatujte si, že řádek, který GNOME říká, že používáme Gjs, musí být vždy na začátku.</p>
  </section>

  <section id="applicationwindow">
    <title>Vytvoření okna aplikace</title>
    <code mime="application/javascript">
class ComboBoxExample {

    // Vytvoří vlastní aplikaci
    constructor() {
        this.application = new Gtk.Application ({
            application_id: 'org.example.jscombobox'});

        // Napojí signály "activate" a "startup" k funkcím zpětného volání
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Funkce zpětného volání pro signál "activate", která zobrazí okno při aktivaci
    _onActivate() {
        this._window.present ();
    }

    // Funkce zpětného volání pro signál "startup", která sestaví uživatelské rozhraní
    _onStartup() {
        this._buildUI ();
    }
</code>
    <p>Všechen kód této ukázky je ve třídě <code>ComboBoxExample</code>. Výše uvedený kód vytvoří <link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link> pro naše widgety a okno, ve kterém budou.</p>
    <code mime="application/javascript">
    // Sestaví uživatelské rozhraní aplikace
    _buildUI() {

        // Vytvoří okno aplikace
        this._window = new Gtk.ApplicationWindow  ({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            title: "Welcome to GNOME",
            default_width: 200,
            border_width: 10 });
</code>
    <p>Funkce <code>_buildUI</code> je místo, ze kterého voláme všechen kód, který vytváří uživatelské rozhraní aplikace. Prvním krokem je vytvoření nového <link xref="GtkApplicationWindow.js">Gtk.ApplicationWindow</link>, do kterého vložíme všechny naše widgety.</p>
  </section>

  <section id="liststore">
    <title>Vytvoření ListStore</title>
    <code mime="application/javascript">
        // Vytvoří ListStore pro vložení našich voleb
        this._listStore = new Gtk.ListStore();
        this._listStore.set_column_types ([
            GObject.TYPE_STRING,
            GObject.TYPE_STRING]);
</code>
    <p>ListStore funguje podobně, jako ten použitý v příkladu <link xref="treeview_simple_liststore.js">TreeView</link>. Dáme mu dva sloupce, oba řetězcové, přičemž jeden z nich bude obsahovat názvy <link href="https://developer.gnome.org/gtk3/3.4/gtk3-Stock-Items.html">standardních ikon Gtk</link>.</p>
    <p>Pokud byste chtěli použít své vlastní ikony, protože nechcete ty zabudované v GNOME, museli byste místo toho použít <file>gtk.gdk.Pixbuf</file>. Zde je pár dalších typů, které můžete použít:</p>
    <list>
      <item><p><file>GObject.TYPE_BOOLEAN</file> – Pravda nebo nepravda</p></item>
      <item><p><file>GObject.TYPE_FLOAT</file> – Desetinné číslo (tj. s plovoucí desetinou čárkou, resp. tečkou)</p></item>
      <item><p><file>GObject.TYPE_STRING</file> – Řetězec písmen a číslic</p></item>
    </list>
    <note style="tip"><p>Abyste mohli používat typy GObject, potřebujete vložit řádek <file>const GObject = imports.gi.GObject;</file> na začátek kódu aplikace tak, jako jsem učinili v tomto příkladu.</p></note>

    <code mime="application/javascript">
        // Toto pole uchovává seznam voleb a jejich ikony
        let options = [{ name: "Select" },
            { name: "New", icon: Gtk.STOCK_NEW },
            { name: "Open", icon: Gtk.STOCK_OPEN },
            { name: "Save", icon: Gtk.STOCK_SAVE }];

        // Vložení voleb do ListStore
        for (let i = 0; i &lt; options.length; i++ ) {
            let option = options[i];
            let iter = this._listStore.append();
            this._listStore.set (iter, [0], [option.name]);
            if ('icon' in option)
                this._listStore.set (iter, [1], [option.icon]);
        }
</code>
    <p>Zde vytváříme pole s textovými volbami a jim odpovídajícími ikonami a pak je vložíme do <code>ListStore</code> více méně stejným způsobem, jako jsem použili pro <code>ListStore</code> v ukázce <link xref="treeview_simple_liststore.js">TreeView</link>. Ikonu chceme vložit jen v případě, že v položce pole opravdu nějaká je, takže to nejprve zkontrolujeme.</p>
    <note style="tip"><p>Položka „Select“ není skutečná volba, ale jen takové pozvání ke kliknutí na náš rozbalovací seznam, a proto nemá ikonu.</p></note>
  </section>

  <section id="combobox">
    <title>Vytvoření ComboBox</title>
    <code mime="application/javascript">
        // Vytvoří rozbalovací seznam
        this._comboBox = new Gtk.ComboBox({
            model: this._listStore});
</code>
    <p>Každý rozbalovací seznam má podkladový „model“ obsahující všechny jeho volby. Pokud máte rozbalovací seznam s rozvětvenými volbami, můžete použít <code>TreeStore</code> (stromové úložiště). V tomto případě používáme již vytvořený <code>ListStore</code> (seznamové úložiště).</p>
    <code mime="application/javascript">
        // Vytvoří vykreslovač buněk pro položky v jednotlivých sloupcích
        let rendererPixbuf = new Gtk.CellRendererPixbuf();
        let rendererText = new Gtk.CellRendererText();

        // Zabalí vykreslovač buněk do rozbalovacího seznamu v pořadí, v jakém je chcem vidět
        this._comboBox.pack_start (rendererPixbuf, false);
        this._comboBox.pack_start (rendererText, false);

        // Nataví vykreslovač buněk, aby se používaly informace z našeho ListStore
        this._comboBox.add_attribute (rendererText, "text", 0);
        this._comboBox.add_attribute (rendererPixbuf, "stock_id", 1);
</code>
    <p>Tato část opět pracuje podobně, jako u vytváření vykreslovačů buněk a balení položek do sloupců u příkladu s <link xref="treeview_simple_liststore.js">TreeView</link>. Největší rozdíl je, že nepotřebujeme vytvářet sloupce rozbalovacího seznamu jako oddělené objekty. Jednoduše zabalíme vykreslovače buněk do <code>ComboBox</code> v pořadí, v jakém chceme objekty zobrazovat, a řekneme jim, že mají informace získávat z <code>ListStore</code> (a typ dat, která očekáváme).</p>
    <p>Používáme <code>CellRendererText</code> pro zobrazení textu a <code>CellRendererPixbuf</code> pro zobrazení ikon. Názvy standardních ikon můžeme uchovávat v podobě řetězců, ale když je potřeba, zobrazíme je pomocí příslušného vykreslovače jako obrázky.</p>
    <note style="tip"><p>Obdobně, jako u <code>TreeView</code>, jsou „model“ (v tomto případě <code>ListStore</code>) a „zobrazení“ (v tomto případě <code>ComboBox</code>) oddělené. Díky tomu můžeme dělat věci, jako je mít sloupce v nějakém pořadí v <code>ListStore</code> a vykreslovače buněk pak zabalit tak, že budou tyto sloupce odpovídat jinému pořadí v <code>ComboBox</code>. Můžeme vytvořit <code>TreeView</code> nebo jiný widget, který zobrazuje informace z <code>ListStore</code> v jiném pořadí, aniž by to ovlivnilo náš rozbalovací seznam.</p></note>

    <code mime="application/javascript">
        // Nastavení prvního řádku v rozbalovacím seznamu, aby byl aktivní po spuštění
        this._comboBox.set_active (0);

        // Napojení signálu „changed“ od rozbalovacího seznamu na naši funkci zpětného volání
        this._comboBox.connect ('changed', this._onComboChanged.bind(this));
</code>
    <p>Chceme, aby součástí byl text „Select“, který lidé uvidí jako první, aby je vyzval ke kliknutí na rozbalovací seznam. Takže jej nastavíme, aby byl aktivní položkou. Dále pak napojíme signál <code>"changed"</code> rozbalovacího seznamu na funkci zpětného volání, takže kdykoliv někdo klikne na novou volbu, něco se stane. V tomto případě jen zobrazíme dialogové okno s drobnou haiku.</p>

    <code mime="application/javascript">
        // Přidá rozbalovací seznam do okna
        this._window.add (this._comboBox);

        // Zobrazí okno a všechny jeho synovské widgety
        this._window.show_all();
    }
</code>
    <p>Nakonec přidáme <code>ComboBox</code> do okna a oknu řekneme ať zobrazí sebe a vše co obsahuje.</p>
  </section>

  <section id="function">
    <title>Funkce, která zpracovává váš výběr</title>
    <code mime="application/javascript">
    _selected() {

        // Bláznivá pseudohaiku, kterou použijeme do dialogového okna se zprávou
        let haiku = ["",
            "You ask for the new\nwith no thought for the aged\nlike fallen leaves trod.",
            "Like a simple clam\nrevealing a lustrous pearl\nit opens for you.",
            "A moment in time\na memory on the breeze\nthese things can't be saved."];
</code>
    <p>Nyní pojďme vytvořit vyskakovací <link xref="messagedialog.js">MessageDialog</link>, který vám zobrazí bláznivou haiku odpovídající tomu, kterou distribuci vyberete. Nejprve vytvoříme pole použitých haiku. Protože první řetězec v našem rozbalovacím seznamu je jen zpráva „Select“, ponecháme první řetězec v poli prázdný.</p>

    <code mime="application/javascript">
        // Která položka v rozbalovacím seznamu je aktivní?
        let activeItem = this._comboBox.get_active();

        // Žádné dialogové okno se zprávou, když zvolíte „Select“
        if (activeItem != 0) {
            this._popUp = new Gtk.MessageDialog ({
                transient_for: this._window,
                modal: true,
                buttons: Gtk.ButtonsType.OK,
                message_type: Gtk.MessageType.INFO,
                text: haiku[activeItem]});

            // Napojí tlačítko OK na zpracující funkci
            this._popUp.connect ('response', this._onDialogResponse.bind(this));

            // Zobrazí dialogové okno se zprávou
            this._popUp.show();
        }

    }
</code>
    <p>Než dialogové okno se zprávou zobrazíme, provedeme test, abychom se ujistili, než není vybrána zpráva „Select“. Pak pro něj nastavíme text haiku z pole, který bude odpovídat aktivní položce v našem rozbalovacím seznamu. To uděláme pomocí metody <code>get_active</code>, která vrací číselné ID výběru.</p>
    <note style="tip"><p>Jinými metodami, které bychom mohli použít jsou <code>get_active_id</code>, která vrací textové ID přiřazené metodou <code>append</code>, a <code>get_active_text</code>, která vrací celý text ve vybrané položce.</p></note>
    <p>Po té, co vytvoříme <code>MessageDialog</code>, napojíme jeho signál <code>"response"</code> na funkci <code>_onDialogResponse</code> a následně řekneme oknu, ať se zobrazí.</p>

    <code mime="application/javascript">
    _onDialogResponse() {

        this._popUp.destroy ();

    }

};
</code>
    <p>Protože jediným tlačítkem, které dialogové okno se zprávou má, je tlačítko <gui>OK</gui>, nepotřebujeme testovat hodnotu <code>response_id</code>, abychom zjistili, na které tlačítko bylo kliknuto. Vše, co uděláme, je, že dialogové okno zlikvidujeme.</p>

    <code mime="application/javascript">
// Spustí aplikaci
let app = new ComboBoxExample ();
app.application.run (ARGV);
</code>
    <p>Nakonec vytvoříme novou instanci konečné třídy ComboBoxExample a aplikaci spustíme.</p>
  </section>

  <section id="complete">
    <title>Úplný kód ukázky</title>
<code mime="application/javascript" style="numbered">#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';

const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;

class ComboBoxExample {

    // Vytvoří vlastní aplikaci
    constructor() {
        this.application = new Gtk.Application ({
            application_id: 'org.example.jscombobox'});

        // Napojí signály "activate" a "startup" k funkcím zpětného volání
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Funkce zpětného volání pro signál "activate", která zobrazí okno při aktivaci
    _onActivate() {
        this._window.present ();
    }

    // Funkce zpětného volání pro signál "startup", která sestaví uživatelské rozhraní
    _onStartup() {
        this._buildUI();
    }

    // Sestaví uživatelské rozhraní aplikace
    _buildUI() {

        // Vytvoří okno aplikace
        this._window = new Gtk.ApplicationWindow  ({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            title: "Welcome to GNOME",
            default_width: 200,
            border_width: 10 });

        // Vytvoří ListStore pro vložení našich voleb
        this._listStore = new Gtk.ListStore();
        this._listStore.set_column_types ([
            GObject.TYPE_STRING,
            GObject.TYPE_STRING]);

        // Toto pole uchovává seznam voleb a jejich ikony
        let options = [{ name: "Select" },
            { name: "New", icon: Gtk.STOCK_NEW },
            { name: "Open", icon: Gtk.STOCK_OPEN },
            { name: "Save", icon: Gtk.STOCK_SAVE }];

        // Vloží volby do ListStore
        for (let i = 0; i &lt; options.length; i++ ) {
            let option = options[i];
            let iter = this._listStore.append();
            this._listStore.set (iter, [0], [option.name]);
            if ('icon' in option)
                this._listStore.set (iter, [1], [option.icon]);
        }

        // Vytvoří rozbalovací seznam
        this._comboBox = new Gtk.ComboBox({
            model: this._listStore});

        // Vytvoří vykreslovače buněk pro položky v jednotlivých sloupcích
        let rendererPixbuf = new Gtk.CellRendererPixbuf();
        let rendererText = new Gtk.CellRendererText();

        // Zabalí vykreslovače buněk do rozbalovacího seznamu v pořadí, v jakém je chcem vidět
        this._comboBox.pack_start (rendererPixbuf, false);
        this._comboBox.pack_start (rendererText, false);

        // Nataví vykreslovače buněk, aby používaly informace z našeho ListStore
        this._comboBox.add_attribute (rendererText, "text", 0);
        this._comboBox.add_attribute (rendererPixbuf, "stock_id", 1);

        // Nastaví první řádek v rozbalovacím seznamu, aby byl aktivní po spuštění
        this._comboBox.set_active (0);

        // Napojí signály „changed“ od rozbalovacího seznamu na naši funkci zpětného volání
        this._comboBox.connect ('changed', this._onComboChanged.bind(this));

        // Přidá rozbalovací seznam do okna
        this._window.add (this._comboBox);

        // Zobrazí okno a všechny jeho synovské widgety
        this._window.show_all();
    }

    _onComboChanged() {

        // Bláznivá pseudohaiku, kterou použijeme do dialogového okna se zprávou
        let haiku = ["",
            "You ask for the new\nwith no thought for the aged\nlike fallen leaves trod.",
            "Like a simple clam\nrevealing a lustrous pearl\nit opens for you.",
            "A moment in time\na memory on the breeze\nthese things can't be saved."];

        // Která položka v rozbalovacím seznamu je aktivní?
        let activeItem = this._comboBox.get_active();

        // Žádné dialogové okno se zprávou, když zvolíte „Select“
        if (activeItem != 0) {
            this._popUp = new Gtk.MessageDialog ({
                transient_for: this._window,
                modal: true,
                buttons: Gtk.ButtonsType.OK,
                message_type: Gtk.MessageType.INFO,
                text: haiku[activeItem]});

            // Napojí tlačítko OK na zpracující funkci
            this._popUp.connect ('response', this._onDialogResponse.bind(this));

            // Zobrazí dialogové okno se zprávou
            this._popUp.show();
        }

    }

    _onDialogResponse() {

        this._popUp.destroy ();

    }

};

// Spustí aplikaci
let app = new ComboBoxExample ();
app.application.run (ARGV);
</code>
  </section>

  <section id="in-depth">
    <title>Dokumentace jdoucí do hloubky</title>
<p>V této ukázce se používá následující:</p>
<list>
  <item><p><link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/stable/GtkApplicationWindow.html">Gtk.ApplicationWindow</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.CellRendererPixbuf.html">Gtk.CellRendererPixbuf</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.CellRendererText.html">Gtk.CellRendererText</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.ComboBox.html">Gtk.ComboBox</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.ListStore.html">Gtk.ListStore</link></p></item>
  <item><p><link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.MessageDialog.html">Gtk.MessageDialog</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.TreeIter.html">Gtk.TreeIter</link></p></item>
</list>
  </section>
</page>
