Hlavní navigace

Gtkmm a jeho spolupráce s Glade

Tomáš Velecký

V tomto díle našeho seriálu o knihovně Gtkmm budou popsány základy práce s programem Glade, návrhářem grafického rozhraní GTK+, od samotného návrhu rozhraní po propojení vygenerovaného XML souboru s konečným výtvorem v kódu C++. Ukázkovým programem je tentokrát opravdu malý a jednoduchý formulář.

Krátké představení

Glade je program, ve kterém se dá jednoduše – pouhým klikáním – vytvořit vzhled nějakého grafického programu. Generuje XML kód, který program dynamicky zpracovává a rozumí mu i člověk, takže můžeme měnit vzhled programu, aniž bychom ho museli překládat. Nejnovější verze Glade pro GTK+ 2 nese číslo 3.8 a pro GTK+ 3 pak číslo 3.10. My se podíváme na 3.8.

Práce s Glade

Glade plugin v Anjutě

Existuje také možnost, jak pracovat s Glade jako s kódem – tak, jak je to např. v Anjutě, kde existuje takový glade plugin (viz screenshot výše). My se vydáme druhou cestou, tedy, jak pracovat s Glade ve smyslu v programu Glade.

Rozhraní

Glade po spuštění

Po spuštění se zobrazí okno s novým, prázdným projektem uprostřed. Po levé straně jsou k dispozici widgety, na pravé straně pak strom se všemi použitými widgety a jejich vlastnosti. Menu je velmi přehledné . V nastavení lze zvolit, zda chceme formát souborů pro GtkBuilder či LibGlade, umístění obrázků a pro kterou verzi GTK+ grafické prostředí děláme. Program je přeložen do češtiny, příručka pro vývojáře ne (naleznete ji v menu Nápověda, jedná se o program DevHelp). Obsahuje plno referencí, mezi kterými je i naše gtkmm. Mně se s ní pracuje lépe než v prohlížeči, protože po levé straně je přehledný strom s widgety. Na jeho červené ikony občas narazíte rovnou v programu, kde plní funkci nápovědy pro daný widget, metodu či signál.

Reference pěkně vedle Glade

Základy

Protože nemůže existovat widget samotný, musíme vždy začít oknem. Jednoduše klikneme na kteroukoli ikonku (tlačítko) ze sekce Nejvyšší úrovně. Uprostřed se objeví požadovaný druh okna a můžeme už přidávat další widgety. Tady je maličká odlišnost, a to ta, že první musíme kliknout na widget (kontejner, …) a potom do volného místa v okně (kontejneru). Mazat lze jak kliknutím na widget uprostřed, tak kliknutím na widget ve stromové struktuře vpravo nahoře a stisknutím klávesy Delete. To je celé.

Volby

Vysvětlení volby

Vpravo dole je okno, ve kterém se nastavují jednotlivé widgety. Samotné volby mají jen krátké popisky, takže člověku nemusí být hned jasné, co vlastně nastavuje. Naštěstí se po najetí myší na kteroukoli volbu zobrazí delší vysvětlení. S delšími popisky to jde hladce, včetně nastavení signálů.

Nastavení signálů

Propojení s programem

Pro práci s těmito XMl soubory nepotřebujeme žádné další knihovny. O vše se stará třída Gtk::Builder, se kterou však musíme pracovat pomocí Glib::RefPtr. O inicializaci se stará metoda create(). Přímo nahrání souboru do paměti provede metoda add_from_file(), které předáme jen cestu k souboru. Abychom mohli s „externím“ widgetem plnohodnotně pracovat (zobrazí se i tak), potřebujeme ukazatel. Ten nám poskytne metoda třídy Gtk::Builder, get_widget(), jejímž prvním argumentem je název (ID) widgetu v Glade (je v kartě Obecné pod položkou Název), v XML kódu, a druhým argumentem pak (zatím nulový) ukazatel v programu. Občas je kód vhodné ošetřit podmínkami nebo výjimkami, viz ukázkový program.

Ukázkový program

#include <gtkmm.h>
#include <iostream>

Gtk::Window* Window_okno = 0;
Gtk::Entry* Entry_Nazev = 0;
Gtk::CheckButton* Checkbutton_Blog = 0;
Gtk::SpinButton* Spinbutton_Uzivatele = 0;
Gtk::Button* Button_Smazat = 0;
Gtk::Button* Button_Dokoncit = 0;

// Tato metoda vynuluje a vymaže všechny pole kromě CheckButtonu
static void on_button1_Smazat_clicked() {
    // Kdyby Entry_Nazev neexistoval (což je možné), mohl by celý program spadnout, proto to radši ověříme podmínkou
    if(Entry_Nazev) {
        Entry_Nazev->set_text("");
    }

    if(Spinbutton_Uzivatele) {
        Spinbutton_Uzivatele->set_value(0);
    }
}

// Vypíše obsah formuláře na terminál a ukončí program
void on_button2_Dokoncit_clicked() {
    if (Checkbutton_Blog && Entry_Nazev && Spinbutton_Uzivatele) {
        if (Checkbutton_Blog->get_active()) {
            std::cout << "Název webové stránky: " << Entry_Nazev->get_text() << std::endl << "Blog: " << "ANO" << std::endl << "Počet předpokládaných uživatelů: " << Spinbutton_Uzivatele->get_value() << std::endl;
        } else {
            std::cout << "Název webové stránky: " << Entry_Nazev->get_text() << std::endl << "Blog: " << "NE" << std::endl << "Počet předpokládaných uživatelů: " << Spinbutton_Uzivatele->get_value() << std::endl;
        }
    } else {
        std::cout << "CHYBA: Pravděpodobně neexistuje některý z potřebných widgetů.\n";
    }

  if(Window_okno) {
    Window_okno->hide();
    }
}

int main (int argc, char **argv) {
  Gtk::Main kit(argc, argv);

    // Nahrání rozhraní ze souboru je trochu více náchylné k chybám, proto ta výjimka
  Glib::RefPtr<Gtk::Builder> refBuilder = Gtk::Builder::create();
  try {
    refBuilder->add_from_file("ui.glade");
  } catch(const Glib::FileError& ex) {
    std::cerr << "Chyba v souboru: " << ex.what() << std::endl;
    return 1;
  } catch(const Gtk::BuilderError& ex) {
    std::cerr << "Chyba třídy Builder: " << ex.what() << std::endl;
    return 1;
  }

  refBuilder->get_widget("window1", Window_okno);
  if(Window_okno) {
        // Toto "získávání" widgetů není pro jejich zobrazení povinné, nicméně s těmito widgety se bude pracovat
        refBuilder->get_widget("entry1_Nazev", Entry_Nazev);
        refBuilder->get_widget("checkbutton1_Blog", Checkbutton_Blog);
        refBuilder->get_widget("spinbutton1_Uzivatele", Spinbutton_Uzivatele);
        Spinbutton_Uzivatele->set_range(0,1000);
        Spinbutton_Uzivatele->set_increments(1,1);
    refBuilder->get_widget("button1_Smazat", Button_Smazat);
        refBuilder->get_widget("button2_Dokoncit", Button_Dokoncit);

    if(Button_Smazat) {
      Button_Smazat->signal_clicked().connect(sigc::ptr_fun(on_button1_Smazat_clicked));
    }

    if(Button_Dokoncit) {
      Button_Dokoncit->signal_clicked().connect(sigc::ptr_fun(on_button2_Dokoncit_clicked));
    }

    kit.run(*Window_okno);
  }

  return 0;
}

Můžete si také stáhnout XML soubor.

Pokračování

Obsahem příštího dílu bude popis práce s tiskárnou a návod, jak si v gtkmm hrát s barvičkami, geometrickými obrazci a vůbec s grafikou. Pokud mě náhodou ještě něco nenapadne nebo si už nikdo nic nebude například ve fóru přát, bude tento díl dílem posledním (o novinkách v gtkmm 3 psát nebudu, jelikož se nezměnilo nic, o čem by již byla v seriálu řeč).

Našli jste v článku chybu?