Blob Blame History Raw
<?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="topic" style="task" id="02_welcome_to_the_grid.js" xml:lang="cs">
  <info>
    <link type="guide" xref="beginner.js#tutorials"/>
    <link type="seealso" xref="grid.js"/>
    <link type="seealso" xref="image.js"/>
    <link type="seealso" xref="label.js"/>
    <revision version="0.1" date="2012-07-28" status="draft"/>

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

    <desc>Naučte se, jak rozvrhnout komponenty uživatelského rozhraní, jako jsou obrázky a popisky.</desc>
  </info>

  <title>2. Vítejte v mřížce</title>
  <synopsis>
    <p>V této lekci si ukážeme, jak vytvořit základní widgety nebo části uživatelského rozhraní GNOME, jako jsou obrázky (Image) a popisky (Label). Po té se naučíte, jak je uspořádat do mřížky (Grid), která vám umožní umístit widgety právě tam, kde je chcete.</p>
    <note style="warning"><p>Prošli jste již <link xref="hellognome.js">první lekcí v této sérii</link>? Než budete pokračovat, bylo by to dobré udělat.</p></note>
  </synopsis>

  <links type="section"/>

  <section id="native">
    <title>Buďme přirození</title>

    <p>V předchozí lekci jsme vytvořili něco, co bylo v podstatě okno GNOME s rámem pro webovou aplikaci. Vše, co jsme se potřebovali naučit z kódu specifického pro GNOME, se točilo okolo vložení WebView – widgetu obsahujícího naši aplikaci – do ApplicationWindow a jak mu říct, aby se zobrazil. K napsání vlastní aplikace byly použity HTML a JavaScript, podobně jako u webových stránek.</p>
    <p>Tentokrát budeme používat jen nativní widgety GNOME. Widget je prostě věc, jako zaškrtávací políčko nebo obrázek, a GNOME jich má širokou nabídku, ze které můžete vybírat. Nazýváme je „nativní“ widgety kvůli odlišení od věcí, jako jsou tlačítka nebo nadpisy ve webové aplikaci, kterou jsme napsali. Protože místo webového kódu použijeme GTK+, půjde o 100% aplikaci GNOME.</p>
    <note style="tip"><p>GTK+ je zkratka pro „GIMP Toolkit“. Je to nástrojová sada widgetů, po kterých můžeme sáhnout, když stavíme naši aplikaci. Původně byly napsány pro <link href="http://www.gimp.org/">GIMP</link>, což je svobodný grafický editor.</p></note>
  </section>

  <section id="setup">
    <title>Nastavení vaší aplikace</title>

    <p>Než začneme tahat widgety z nástrojové sady GTK+, musíme nejdříve napsat základní kód, který aplikace vyžaduje a tak se s ním setkáte často.</p>
    <code mime="application/javascript">
#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;
</code>
    <p>Tato část je vždy na začátku kódu. V závislosti na tom, co přesně hodláte dělat, zde můžete deklarovat i další importy. To, co píšeme teď, je docela jednoduché, takže nám to bude stačit takto. Gtk pro widgety používající stabilní API 3.0.</p>
    <p>Když už o tom mluvíme:</p>
    <code mime="application/javascript">
class WelcomeToTheGrid {
    // Vytvoří vlastní aplikaci
    constructor() {
        this.application = new Gtk.Application();

        // 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" zobrazující okno při aktivaci
    _onActivate: function () {
        this._window.present ();
    },

    // Funkce zpětného volání pro signál "startup" sestavující uživatelské rozhraní
    _onStartup: function () {
        this._buildUI ();
    },
</code>
    <p>Toto je začátek vlastní aplikace a funkce <code>_init</code> ji vytvoří. Aplikace pak řekne funkci <code>_buildUI</code>, aby vytvořila ApplicationWindow, který budeme nazývat <var>_window</var> a našemu oknu se říká, aby se zobrazilo, kdykoliv je potřeba.</p>
    <p>Tato část je opět do značné míry vytvořena stylem kopírovat-a-vložit, akorát je potřeba dát aplikaci vždy jedinečný název.</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,
            border_width: 10,
            title: "Welcome to the Grid"});
</code>
    <p>Nakonec spustíme funkci <code>_buildUI</code> vytvořením nového ApplicationWindow. Určíme naší aplikaci, že se má objevit uprostřed obrazovky a že by mělo být nejméně 10 pixelů mezi vnější hranou a widgety uvnitř. Rovněž ji přidělíme název, který se objeví v záhlaví okna.</p>
  </section>

  <section id="toolbox">
    <title>Po čem sáhnout do nástrojové sady GTK+</title>
    <p>Které widgety bychom měli použít? Řekněme, že chceme napsat aplikaci, která vypadá nějak takto:</p>

    <media type="image" mime="image/png" src="media/02_jsgrid_01.png"/>

    <p>K tomu budeme potřebovat aspoň obrázek a textový popisek. Začněme obrázkem:</p>
    <code mime="application/javascript">
        // Vytvoří obrázek
        this._image = new Gtk.Image ({ file: "gnome-image.png" });
</code>

    <p>Obrázek použitý v tomto příkladu si můžete stáhnout <link href="https://live.gnome.org/TarynFox?action=AttachFile&amp;do=get&amp;target=gnome-image.png">zde</link>. Zajistěte, aby byl uložený ve stejné složce, jako kód, který píšete.</p>

    <code mime="application/javascript">
        // Vytvoří popisek
        this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!" });
</code>
    <p>Tento kód pod něj přidá popisek. Zde můžete vidět, jak se vytváří widgety. Všechny jsou součástí Gtk a mi jim udáváme vlastnosti, kterými si přizpůsobíme, jak se mají chovat. V tomto případě widgetu Image nastavíme vlastnost <code>file</code> na název souboru s obrázkem a popisku vlastnost <code>label</code> na větu, kterou chceme mít pod obrázkem.</p>
    <note style="tip"><p>Ano, to že má Label vlastnost label vypadá jako zdvojování, ale není tomu tak. Ostatní widgety, které obsahují text, mají vlastnost <code>label</code>, takže kvůli <em>jednotnosti</em> je tomu tak i u widgetu Label.</p></note>
    <p>Tyto widgety nemůžeme do našeho okna jen tak přidat ve správném pořadí, podobně jako se to dělá s prvky HTML na webové stránce. Kvůli tomu, že ApplicationWindow může obsahovat jen jeden widget.</p>
    <p>Co s tím? Vytvoříme kontejnerový widget, který může obsahovat více než jeden widget a umí je uspořádat. Pohleďte: mřížka.</p>
    <code mime="application/javascript">
        // Vytvoří mřížku
        this._grid = new Gtk.Grid ();
</code>

    <p>Neudali jsme jí žádné vlastnosti. To uděláme až později, až se naučíme s mřížkou pořádně zacházet. Nejprve pojďme do námi vytvořené mřížky připojit obrázek a popisek.</p>
    <code mime="application/javascript">
        // Připojení obrázku a popisku do mřížky
        this._grid.attach (this._image, 0, 0, 1, 1);
        this._grid.attach (this._label, 0, 1, 1, 1);
</code>

    <p>Tento kód vypadá strašně složitě, ale není tomu tak. Zde je popsáno, co jednotlivá čísla znamenají:</p>
    <list type="numbered">
      <item><p><em>První</em> číslo je pozice ve směru zleva doprava, na kterou se má widget umístit, počínaje od 0. Widget, který použije 0, patří úplně doleva.</p></item>
      <item><p><em>Druhé</em> číslo je pozice ve směru shora dolů, na kterou se má daný widget umístit, počínaje od 0. Popisek má být pod obrázkem, takže widget Image dostane pozici 0 a Label pozici 1.</p></item>
      <item><p><em>Třetí</em> a <em>čtvrté</em> číslo udává kolik sloupců a řádků má widget okupovat. Za minutku uvidíme, jak to funguje.</p></item>
    </list>

    <code mime="application/javascript">
        // Přidá mřížku do okna
        this._window.add (this._grid);

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

};

// Spustí aplikaci
let app = new WelcomeToTheGrid ();
app.application.run (ARGV);
</code>
    <p>Nyní máme vytvořenou mřížku a do ní připojené všechny naše widgety, přidali jsme ji do okna a oknu, jako poslední část funkce _buildUI, řekli, ať se zobrazí. Jako vždy končíme vytvořením nové instance třídy aplikace a jejím spuštěním.</p>
    <p>Uložte svoji aplikaci jako <file>welcome_to_the_grid.js</file>. Následně ji spusťte tak, že otevřete terminál, přepnete se do složky, ve které je vaše aplikace, a napíšete:</p>
      <screen> <output style="prompt">$ </output>gjs welcome_to_the_grid.js </screen>

    <media type="image" mime="image/png" src="media/02_jsgrid_02.png"/>

    <p>Ono to funguje! Ale… Nevypadá to úplně hezky. Proč je popisek nalepený těsně na obrázek? To jednak není estetické a jedna se to špatně čte. Co s tím můžeme udělat?</p>
  </section>

  <section id="tweaking">
    <title>Vyladění mřížky</title>

    <p>Jedna z věcí, kterou můžeme udělat, je udat popisku při vytváření vlastnost <code>margin_top</code>. Funguje to podobně, jako nastavení vlastnosti „margin“ u prvků HTML pomocí stylování CSS.</p>
    <code mime="application/javascript">
        // Vytvoří popisek
        this._label = new Gtk.Label ({
            label: "Welcome to GNOME, too!",
            margin_top: 20 });
</code>

    <p>Samozřejmě, že když popisek nahradíme něčím jiným, nebo přidáme další widget, musíme nastavení <code>margin_top</code> zopakovat i u něj. Jinak s končíme s něčím takovýmto:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_03.png"/>

    <p>Mohli bychom udat vlastnost <code>margin_bottom</code> u obrázku, ale to by nefungovalo správně, když by nový popisek byl v jiném sloupci. Takže pojďme to místo toho zkusit takto:</p>
    <code mime="application/javascript">
        // Vytvoří mřížku
        this._grid = new Gtk.Grid ({
            row_spacing: 20 });
</code>

    <p>To zajistí, že vodorovně mezi všemi řádky bude vždy prostor 20 pixelů.</p>
    <note style="tip"><p>Ano, obdobně můžeme nastavit vlastnost mřížky <code>column_spacing</code> nebo vlastnosti <code>margin_left</code> a <code>margin_right</code> u libovolného widgetu. Jestli chcete, vyzkoušejte si to!</p></note>
  </section>

  <section id="adding">
    <title>Přidání dalších widgetů</title>

    <p>Pokud bychom chtěli přidat druhý popisek, jak bychom to vlastně měli udělat, aby to na pohled vypadalo, že tam patří? Jedním ze způsobů je obrázek nahoře umístit na střed, tak aby byl nad oběma popisky a ne jen nad jedním vlevo. To je ta situace, kdy ostatní čísla u metody pro připojení do mřížky, přijdou vhod:</p>
    <code mime="application/javascript">
        // Vytvoří druhý popisek
        this._labelTwo = new Gtk.Label ({
            label: "The cake is a pie." });

        // Připojí obrázek a popisky do mřížky
        this._grid.attach (this._image, 0, 0, 2, 1);
        this._grid.attach (this._label, 0, 1, 1, 1);
        this._grid.attach (this._labelTwo, 1, 1, 1, 1);
</code>

    <p>Po té, co vytvoříme druhý popisek, připojíme jej do mřížky napravo od prvního popisku. Pamatujete, že první dvě čísla udávají číslo sloupce a řádku zleva doprava a shora dolů, počítáno od 0? Takže, když je první popisek v sloupci 0 a řádku 1, můžeme vložit druhý do sloupce 1 a řádku 1, aby byl napravo od prvního.</p>
    <p>Podívejme se na číslo 2 ve výrazu pro připojení obrázku. V něm je ten trik. Toto číslo znamená, přes kolik sloupců se obrázek roztáhne, pamatujete? Takže, když to dáme vše dohromady, dostaneme něco takového:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_04.png"/>

    <p>Jsou zde dvě věci, které byste měli vzít na vědomí.</p>
    <list>
      <item><p>Natavení obrázku, aby zabíral dva sloupce, přímo obrázek nijak neroztáhne. Místo toho roztáhne neviditelný box obsazený widgetem Image tak, aby zaplnil oba sloupce a obrázek pak umístí do středu tohoto boxu.</p></item>
      <item><p>I když jsme nastavili vlastnosti <code>row_spacing</code> u mřížky a <code>border_width</code> u okna aplikace, nemáme zatím nic, co by vložilo okraj mezi dva popisky. Dříve byly odděleny díky tomu, že obrázek zabíral jen jeden sloupec, ale nyní, když je roztažen přes oba sloupce, nevidí GNOME důvod k tomu, držet popisky oddělené.</p></item>
    </list>

    <p>Existují aspoň tři způsoby, jak vyřešit druhou záležitost. Jako první můžeme nastavit u jednoho z popisků <code>margin_left</code> nebo <code>margin_right</code>:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_05.png"/>

    <p>Zadruhé můžeme nastavit vlastnost mřížky <code>column_homogenous</code> na <code>true</code>.</p>
    <code mime="application/javascript">
        // Vytvoří mřížku
        this._grid = new Gtk.Grid ({
            column_homogeneous: true,
            row_spacing: 20 });
</code>

    <p>Ve výsledku to bude vypadat nějak takto:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_06.png"/>

    <p>A zatřetí můžeme nastavit vlastnost mřížky <code>column_spacing</code>, stejným způsobem jako její vlastnost <code>row_spacing</code>.</p>
    <code mime="application/javascript">
        // Vytvoří mřížku
        this._grid = new Gtk.Grid ({
            column_spacing: 20,
            row_spacing: 20 });
</code>
    <p>Ve výsledku to bude vypadat takto:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_07.png"/>
  </section>

  <section id="stock">
    <title>Používání standardních obrázků</title>

    <p>GNOME má připravenou spoustu standardních obrázků, které můžete použít, kdy se necítíte na vytvoření vlastních nebo chcete použít obecně známou ikonu. Zde je, jak vytvořit standardní obrázek, pro srovnání s tím, jak vytvořit ten normální:</p>
    <code mime="application/javascript">
        // Vytvoří obrázek
        this._image = new Gtk.Image ({ file: "gnome-image.png" });

        // Vytvoří druhý obrázek pomocí standardní ikony
        this._icon = new Gtk.Image ({ stock: 'gtk-about' });
</code>
    <p>Po té jej připojíme do mřížky nalevo od prvního popisku. (V tomto příkladu nevyužijeme druhý popisek.)</p>
    <code mime="application/javascript">
        // Připojí obrázky a popisek do mřížky
        this._grid.attach (this._image, 0, 0, 2, 1);
        this._grid.attach (this._icon,  0, 1, 1, 1);
        this._grid.attach (this._label, 1, 1, 1, 1);
</code>
    <p>Po spuštění dostaneme něco takového:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_08.png"/>

    <p>Je to to, co vypadá jako standardní ikona „O aplikaci“ (About). Na seznam všech standardních položek, počínaje gtk-about, se můžete podívat v <link href="https://developer.gnome.org/gtk3/3.4/gtk3-Stock-Items.html#GTK-STOCK-ABOUT:CAPS">dokumentaci pro vývojáře GNOME</link>. Byla napsána pro programátory v jazyce C, ale ten nepotřebujete znát k tomu, abyste ji mohli používat. Stačí se jen podívat na část v uvozovkách, jako je "gtk-about" a tuto část zkopírovat, když chcete použít ikonu vedle ní.</p>
    <note style="tip"><p>Okolo 'gtk-about' jsem v kódu použili jednoduché uvozovky, protože na rozdíl od jiných textových řetězců, které máme v dvojitých uvozovkách, tento nebude nikdy potřeba překládat do jiného národního jazyka. Ve skutečnosti, kdyby <em>byl</em> přeložen, tak by došlo k porušení ikony, protože její název musí být pořád "gtk-about", bez ohledu na jazyk, ve kterém je uživatelské rozhraní.</p></note>
  </section>


  <section id="next">
    <title>A co dál?</title>
    <p>Než přikročíme k další lekci, zkusme něco udělat trochu jinak:</p>
    <code mime="application/javascript">
        // Vytvoří tlačítko
        this._button = new Gtk.Button ({
            label: "Welcome to GNOME, too!"});

        // Připojí obrázky a tlačítka do mřížky
        this._grid.attach (this._image,  0, 0, 2, 1);
        this._grid.attach (this._icon,   0, 1, 1, 1);
        this._grid.attach (this._button, 1, 1, 1, 1);
</code>

    <p>Je to pravda, změnili jsme popisek na tlačítko jen pouhou změnou názvu widgetu! Zjistíte však, že když aplikaci spustíte a kliknete na něj, nic nedělá. Jak jej přimět, aby něco dělalo? To je to, co se dozvíte v <link xref="03_getting_the_signal.js">naší následující lekci</link>.</p>
    <p>Jestli se vám to líbí, zkuste věnovat nějaký čas experimentování s mřížkami, popisky a obrázky, včetně standardních obrázků.</p>
    <note style="tip"><p>Jedním z triků, jak vytvořit složitější rozvržení, je vnoření mřížek do sebe. To umožňuje seskupit dohromady související widgety a snadno měnit jejich uspořádání. Pokud vás zajímá, jak se to dělá, podívejte na na ukázkový kód k widgetu <link xref="radiobutton.js">RadioButton</link>.</p></note>
  </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 Gtk = imports.gi.Gtk;

class WelcomeToTheGrid {

    // Vytvoří vlastní aplikaci
    constructor() {
        this.application = new Gtk.Application();

    // 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" zobrazujicí okno při aktivaci
    _onActivate() {
        this._window.present();
    },

    // Funkce zpětného volání pro signál "startup" sestavující 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,
            border_width: 10,
            title: "Welcome to the Grid"});

        // Vytvoří mřížku
        this._grid = new Gtk.Grid ({
            // column_homogeneous: true,
            // column_spacing: 20,
            row_spacing: 20 });

        // Vytvoří obrázek
        this._image = new Gtk.Image ({ file: "gnome-image.png" });

        // Vytvoří druhý obrázek pomocí standardní ikony
        this._icon = new Gtk.Image ({ stock: 'gtk-about' });

        // Vytvoří popisek
        this._label = new Gtk.Label ({
            label: "Welcome to GNOME, too!",
            /* margin_top: 20 */ });

        /* Vytvoří druhý popisek
        this._labelTwo = new Gtk.Label ({
            label: "The cake is a pie." }); */

        /* Vytvoří tlačítko
        this._button = new Gtk.Button ({
            label: "Welcome to GNOME, too!"}); */

        // Připojí obrázek a tlačítka do mřížky
        this._grid.attach (this._image,  0, 0, 2, 1);
        this._grid.attach (this._icon,   0, 1, 1, 1);
        this._grid.attach (this._label,  1, 1, 1, 1);

        // this._grid.attach (this._label, 0, 1, 1, 1);
        // this._grid.attach (this._labelTwo, 1, 1, 1, 1);

        // this._grid.attach (this._button, 1, 1, 1, 1);

        // Přidá mřížku do okna
        this._window.add (this._grid);

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

};

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

</page>