Hierarchický seznam používáme v aplikacích pro tok informací oběma směry - od uživateli k aplikaci i naopak. Knihovna Gtk2 umožňuje vytvářet aplikace nejen s editovatelnými položkami, ale i editovatelnou hierarchií. Jednodušší variantu výběru ze seznamu pak Gtk2 nabízí ještě ve formě dalšího widgetu.
3.2.2011 00:00 | Jiří Václavík | přečteno 10674×
TreeView je widget s položkami v hierarchické struktuře a umožňuje uživateli následující činnosti.
Nejprve obvykle vytváříme objekt typu Gtk2::TreeStore. Metodou Gtk2::TreeStore->append v něm tvoříme jednotlivé položky, k nimž nastavujeme popisky voláním Gtk2::TreeStore->set. Z tohoto objektu pak tvoříme Gtk2::TreeView. Je třeba ještě vytvořit příslušný počet sloupců a poté již můžeme výsledek zobrazit.
Zvykem bývá umísťovat TreeView do Gtk2::ScrolledWindow, což je okno s posuvníky. To proto, že uživatel se může rozbalováním nabídek často dostat mimo obrazovku.
Vytvořme tedy hlavní okno a do něj okno s posuvníky.
$okno = Gtk2::Window->new("toplevel");
$okno->set_border_width(20);
$okno->set_title("treeview");
$scrolled = Gtk2::ScrolledWindow->new(undef, undef);
$scrolled->set_size_request(150, 200);
$okno->add($scrolled);
#zde vytvoříme strom
$okno->show_all;
Gtk2->main;
TreeStore vytvoříme standardně. Vložme do něj pět položek s tím, že poslední dvě budou podřízené druhé. Syntaxe je intuitivní.
my $tree_store = Gtk2::TreeStore->new(qw(Glib::String));
my $iter1 = $tree_store->append(undef);
my $iter2 = $tree_store->append(undef);
my $iter3 = $tree_store->append(undef);
my $iter21 = $tree_store->append($iter2);
my $iter22 = $tree_store->append($iter2);
$tree_store->set($iter1,0 => "Polozka 1");
$tree_store->set($iter2,0 => "Polozka 2");
$tree_store->set($iter3,0 => "Polozka 3");
$tree_store->set($iter21,0 => "Polozka 2.1");
$tree_store->set($iter22,0 => "Polozka 2.2");
Z této struktury vytvoříme TreeView.
my $tree = Gtk2::TreeView->new($tree_store);
Zbývá nám přidat sloupce. Zatím ponechme bez komentáře následující řádky.
my $tree_column = Gtk2::TreeViewColumn->new();
my $renderer = Gtk2::CellRendererText->new;
$tree_column->pack_start($renderer, FALSE);
$tree_column->add_attribute($renderer, text => 0);
Přidejme ještě titulek sloupce.
$tree_column->set_title("Seradit");
TreeView umí automaticky řadit položky podle určeného sloupce. Určeme ho tedy.
$tree_column->set_sort_column_id(0);
Též můžeme uživateli dovolit, aby metodou drag&drop přesunoval položky.
$tree->set_reorderable(TRUE);
Na závěr musíme náš strom přidat do okna.
$scrolled->add($tree);
To je základní použití TreeView.
TreeView po drag&drop přesunutí jedné z položek
Zkusme změnit položky nabídky na editovatelné. K tomu slouží tento příkaz.
$renderer->set_property("editable", TRUE);
Vyzkoušíme-li, zjistíme, že sice položky editovatelné jsou, ale po kliknutí někam pryč se zase vrátí původní text. To je sice v pořádku, ale většinou to nechceme.
Jak to napravit? Používá se na to speciální signál edited, který je emitován právě v okamžiku, kdy k editaci pole došlo.
$renderer->signal_connect(edited => \&zmen_polozku, $tree_store);
Z toho plyne, že tedy musíme sami napsat funkci, která se nám o změnu textu v položce postará. Zavoláme set_value nad Gtk2::TreeStore. Při volání musíme znát lokalizaci položky ve stromu, sloupec (získáme z $bunka->get_data) a samozřejmě nový text.
sub zmen_polozku {
my($bunka, $lok_string, $zmeneno_na, $store) = @_;
$store->set_value($store->get_iter(Gtk2::TreePath->new_from_string($lok_string)), 0, $zmeneno_na);
}
Další vlastností TreeView je, že umí dělat výběry položek. Existuje několik módů. Buď vybírat vůbec nejde (none), jde vybírat jedna položka (single) nebo více položek (multiple). Seznam módů je uchován v Gtk2::SelectionMode.
Výběr je objekt typu Gtk2::TreeSelection a získáme ho metodou get_selection zavolanou nad Gtk2::TreeView. Mód výběru nastavujeme pomocí Gtk2::TreeSelection->set_mode.
Metodou get_selected získáme objekt typu Gtk2::TreeIter, jsme-li v módu single. Jsme-li v módu multiple, pak použijeme metodu get_selected_rows. Ta vrátí seznam Gtk2::TreeIter objektů.
Dost divoké věci můžeme dělat s Renderery. Existuje více druhů (nejen pro text). Zde se odkážeme na dokumentaci. Ukažme si jediný jednoduchý příklad, který přebarví pozadí buněk na zeleno.
$renderer->set_property("cell-background", "green");
Rozbalovací nabídka je widget typu Gtk2::ComboBox. Vytvoření probíhá intuitivně.
my $combobox = Gtk2::ComboBox->new_text;
$combobox->append_text("Polozka 1");
$combobox->append_text("Polozka 2");
$combobox->append_text("Polozka tri");
$combobox->append_text("Polozka 4");
$combobox->set_active(2); #druhá položka bude zaškrtnuta implicitně
Podívejme se, jak ComboBox vypadá.
ComboBox
Jakmile uživatel změní položku, emituje to signál changed. Odchyťme ho.
$combobox->signal_connect("changed" => \&combobox);
Pomocí $combobox->get_active pak získáme aktuální hodnotu.
K vytvoření comboboxu můžeme využít také Gtk2::ListStore. To je podobně jako Gtk2::TreeStore struktura položek.
my $list_store = Gtk2::ListStore->new(qw(Glib::String));
$iter1 = $list_store->append;
$list_store->set($iter1,0,"popisek 0");
$iter2 = $list_store->append;
$list_store->set($iter2,0,"popisek 1");
I zde pak můžeme používat triky s renderery.
my $combobox = Gtk2::ComboBox->new($list_store);
my $renderer = Gtk2::CellRendererText->new();
$renderer->set_property("cell-background", "green");
$combobox->pack_start($renderer, TRUE);
$combobox->add_attribute($renderer,"text",0);
Chceme-li získat editovatelnost, pak použijeme widget Gtk2::ComboBoxEntry. Vše ostatní zůstává stejné. Akorát je opět nutné odchytit signál changed a zajistit přepis položek.