# ComboBox (JavaScript)

Taryn Fox
jewelfox@fursona.net 2012
Přizpůsobitelná rozbalovací nabídka

# ComboBox

`ComboBox` (rozbalovací seznam) je vysoce přizpůsobitelná rozbalovací nabídka. Obsahuje obdobu widgetu TreeView, který se objeví po kliknutí, doplněného modelem `ListStore` (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áš `ListStore` 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.

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.

Práce s `ListStore` zabere nějaký čas. Jestli chcete jen jednoduchou čistě textovou rozbalovací nabídku, podívejte se na ComboBoxText. Jeho vytvoření nezabere tolik času a jednodušeji se s ním pracuje.

# Importované knihovny

#!/usr/bin/gjs

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

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

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.

# Vytvoření okna aplikace

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 (); }

Všechen kód této ukázky je ve třídě `ComboBoxExample`. Výše uvedený kód vytvoří Gtk.Application pro naše widgety a okno, ve kterém budou.

// 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 });

Funkce `_buildUI` 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 Gtk.ApplicationWindow, do kterého vložíme všechny naše widgety.

# Vytvoření ListStore

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

ListStore funguje podobně, jako ten použitý v příkladu TreeView. Dáme mu dva sloupce, oba řetězcové, přičemž jeden z nich bude obsahovat názvy standardních ikon Gtk.

Pokud byste chtěli použít své vlastní ikony, protože nechcete ty zabudované v GNOME, museli byste místo toho použít gtk.gdk.Pixbuf. Zde je pár dalších typů, které můžete použít:

GObject.TYPE_BOOLEAN – Pravda nebo nepravda

GObject.TYPE_FLOAT – Desetinné číslo (tj. s plovoucí desetinou čárkou, resp. tečkou)

GObject.TYPE_STRING – Řetězec písmen a číslic

Abyste mohli používat typy GObject, potřebujete vložit řádek const GObject = imports.gi.GObject; na začátek kódu aplikace tak, jako jsem učinili v tomto příkladu.

// 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 < 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]); }

Zde vytváříme pole s textovými volbami a jim odpovídajícími ikonami a pak je vložíme do `ListStore` více méně stejným způsobem, jako jsem použili pro `ListStore` v ukázce TreeView. Ikonu chceme vložit jen v případě, že v položce pole opravdu nějaká je, takže to nejprve zkontrolujeme.

Položka „Select“ není skutečná volba, ale jen takové pozvání ke kliknutí na náš rozbalovací seznam, a proto nemá ikonu.

# Vytvoření ComboBox

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

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 `TreeStore` (stromové úložiště). V tomto případě používáme již vytvořený `ListStore` (seznamové úložiště).

// 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);

Tato část opět pracuje podobně, jako u vytváření vykreslovačů buněk a balení položek do sloupců u příkladu s TreeView. 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 `ComboBox` v pořadí, v jakém chceme objekty zobrazovat, a řekneme jim, že mají informace získávat z `ListStore` (a typ dat, která očekáváme).

Používáme `CellRendererText` pro zobrazení textu a `CellRendererPixbuf` 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.

Obdobně, jako u `TreeView`, jsou „model“ (v tomto případě `ListStore`) a „zobrazení“ (v tomto případě `ComboBox`) oddělené. Díky tomu můžeme dělat věci, jako je mít sloupce v nějakém pořadí v `ListStore` a vykreslovače buněk pak zabalit tak, že budou tyto sloupce odpovídat jinému pořadí v `ComboBox`. Můžeme vytvořit `TreeView` nebo jiný widget, který zobrazuje informace z `ListStore` v jiném pořadí, aniž by to ovlivnilo náš rozbalovací seznam.

// 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));

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 `"changed"` 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řidá rozbalovací seznam do okna this._window.add (this._comboBox);

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

Nakonec přidáme `ComboBox` do okna a oknu řekneme ať zobrazí sebe a vše co obsahuje.

# Funkce, která zpracovává váš výběr

_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."];

Nyní pojďme vytvořit vyskakovací MessageDialog, 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ý.

// 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(); }

}

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 `get_active`, která vrací číselné ID výběru.

Jinými metodami, které bychom mohli použít jsou `get_active_id`, která vrací textové ID přiřazené metodou `append`, a `get_active_text`, která vrací celý text ve vybrané položce.

Po té, co vytvoříme `MessageDialog`, napojíme jeho signál `"response"` na funkci `_onDialogResponse` a následně řekneme oknu, ať se zobrazí.

_onDialogResponse() {

this._popUp.destroy ();

}

};

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

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

Nakonec vytvoříme novou instanci konečné třídy ComboBoxExample a aplikaci spustíme.

# Úplný kód ukázky

#!/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 < 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);

# Dokumentace jdoucí do hloubky

V této ukázce se používá následující:

Gtk.Application

Gtk.ApplicationWindow

Gtk.CellRendererPixbuf

Gtk.CellRendererText

Gtk.ComboBox

Gtk.ListStore

Gtk.MessageDialog

Gtk.TreeIter