Kategória: ObjectPascal

Zmenené: 27. marec 2011

TTreeView

TTreeView je komponent, ktorý je súčasťou LCL (Lazarus Component Library), a slúži na zobrazovanie stromovej štruktúry dát. V Lazarovi ho nájdete v palete komponentov na záložke Common controls. Ako ho však používať?

Okrem už spomínanej triedy TTreeView si v tomto článku predstavíme triedu TTreeNodes, ktorá je kolekciou tried TTreeNode, z ktorých každá reprezentuje jednu položku stromovej štruktúry.

Stromová štruktúra

Neviete čo je to stromová štruktúra dát? Ale určite viete! Iste ste už videli štruktúru adresárov. Všetky adresáre začínajú v jednom mieste (v Linuxe doslova v jednom mieste, vo Windows v jednom mieste na každom disku). Toto jedno miesto sa volá koreň (root). Tento koreň môže obsahovať adresáre alebo súbory. Súbory teraz necháme bokom a pozrieme sa na adresáre. Každý adresár môže znova obsahovať adresáre a súbory, a takto to môže pokračovať ďalej. Všimnite si, že koreň sa rozvetvuje na jednotlivé adresáre, a tie sa rozvetvujú na podadresáre, ktoré sa môžu rozvetvovať tiež.

Pri takomto vetvení má každý adresár a podadresár (okrem koreňa) svojho, presne určeného, predchodcu, ktorému vravíme nadradený adresár. A každý adresár môže mať svojho potomka, ktorému vravíme podaddresár (spomínal som, že súbory vynecháme). Takáto dátová štruktúra sa ani zďaleka nevyužíva len pri adresárovej štruktúre a práve takúto štruktúru zobrazuje prvok TTreeView. Aj v tomto prvku máme jeden koreň, ktorý môže obsahovať položky, a tie zase môžu obsahovať podpoložky…

../../_images/ttree_formular.png

Pre naše pokusy si pripravte formulár s jedným prvkom TTreeView, jedným prvkom TImageList a tromi tlačítkami. Prípadne ešte jedno tlačidlo na zatváranie programu, ale bez toho sa zaobídeme. Pripravený formulár môže vyzerať napríklad tak ako na obrázku. Ten ktorý vidíte už má pridané uzly aj s nastavenými obrázkami, tak trochu ako motivácia. Pre väčšiu názornosť som nepremenoval prvok TTreeView, ostatné prvky som nastavil takto:

Nastavenie prvkov formulára

Typ Meno Popis
TTreeView TreeView1
TImageList imlTreeView
TButton btnAdd Pridať
TButton btnPodr Podriadený
TButton btnRemove Odstrániť

Pridávanie položiek

../../_images/editorpoloziek.png

Položky do komponentu TTreeView možno pridávať dvomi spôsobmi, a to v dobe návrhu a za behu programu. Na pridávanie položiek v dobe návrhu možno použiť nástroj Editor položiek TTreeView. Tento editor vyvoláte dvojklikom na prvok TTreeView v okne formulára alebo na tlačidlo s tromi bodkami pri vlastnosti Items, v okne Inšpektora objektov. Obomi spôsobmi otvoríte spomínané okno, ktoré vyzerá takto:

Ako sa mi vidíte, okno je rozdelené na dve časti. V ľavej časti môžete manipulovať s jednotlivými položkami zoznamu. Môžete ich pridávať, mazať. Môžete si ich aj uchovať v externom súbore, či z takého súboru znova načítať. V pravej časti zase môžete nastavovať vlastnosti jednotlivých položiek, a to zobrazený text, index obrázka v pridruženom prvku TImageList a takisto index výberu a stavu.

Programová manipulácia s položkami

Takéto statické pridávanie položiek je v mnohých aplikáciach nedostatočné, pretože pri vytváraní programu neviem, čo všetko bude prvok TTreeView obsahovať, veď si predstavte, že by taký prieskumník súborov obsahoval dopredu pripravené zložky… Inými slovami, potrebujeme možnosť pridávať položkyza behu programu. To je samozrejme možné a nie je to nijako zložité. Pri pridávaní položiek budeme pracovať s triedou TTreeNodes, ktorá je v prvku TTreeView sprístupnená pomocou vlastnosti Items. Trieda TTreeNodes je kolekciou tried TTreeNode a pre pridávanie prvkov poskytuje niekoľko metód:

  • Add pridáva uzol na rovnakej úrovni;
  • AddFirst pridáva uzol ako prvý uzol rovnakej úrovne;
  • AddChild pridáva podriadený uzol;
  • AddChildFirst pridáva podriadený uzol ako prvý podriadený uzol.

Všetky tieto metódy robia v podstate rovnakú vec. Pridávajú položku stromovej štruktúry, ako ste si iste všimli, takémuto prvku sa v stromovej štruktúre vraví uzol (node). Všetky tieto metódy majú svoj objektový ekvivalent, ktorý umožňuje pridať uzol spolu s odkazom na dátový objekt. Pridanie nového uzla do koreňa stromu by teda mohlo vyzerať takto:

Koreňový uzol

InputQuery( 'Nový uzol', 'Zadajte meno uzla:', sText );
with TreeView1.Items.AddFirst( nil, sText ) do
begin
    Selected := true;
end;

Tento príklad si najprv pomocou dialógu InputQuery vyžiada meno pre uzol a potom vytvorí nový uzol v koreni stromu so zadaným menom. A keďže používame metódu AddFirst, je uzol pridaný ako prvý. To, že je uzol vytvorený v koreni zabezpečí práve prvý parameter metódy AddFirst, teda hodnota nil, zobrazovaný text je predaný ako druhý parameter.

Takéto správanie isto nie je postačujúce. Určite nájdete veľa dôvodov na to, aby bol nový uzol pridávaný na určité miesto. Pre určenie východzieho uzla na pridanie existuje viacero spôsobov. V nasledujúcom príklade ukážem ten, v ktorom za východzí použijeme uzol, ktorý je vybratý, na čo nám poslúži vlastnosť Selected triedy TCustomTreeView.

Pridanie na zvolené miesto

if ( TreeView1.Selected = nil ) then
begin
    ShowMessage( 'Vyberte uzol' );
end else
begin
    InputQuery( 'Nový uzol', 'Zadajte meno uzla:', sText );
    with TreeView1.Items.AddFirst( TreeView1.Selected, sText ) do
    begin
        MakeVisible;
    end;
end;

Samozrejme, na začiatku je potrebná kontrola, či je vôbec nejaký prvok vybratý. Ak by sme ju neurobili, nič by sa nestalo, len by bol uzol znova vytvorený v koreni stromu. Ak nahradíte metódu AddFirst za AddChildFirst, kód bude vytvárať podriadený uzol. Dobre, toľko o pridávaní, často však je potrebné položky nie len pridávať, ale ich aj odstraňovať. K tomu je predurčená metóda Delete, ktorej použite môže vyzerať takto:

Odstránenie vybranej položky

if ( TreeView1.Selected = nil ) then
begin
    ShowMessage( 'Vyberte položku' );
end else
begin
    TreeView1.Selected.Delete;
end;

V tomto prípade kontrolu, či je nejaká položka vybraná urobiť musíme, inak by nastala chyba prístupu (Access Violation), pretože by sme volali metódu Delete neexistujúcej triedy. Obdobné je použitie metódy DeleteChildren, ktorej úlohou je zmazať len podriadené uzly.

Obrázky položiek

Každá položka môže mať pridelený obrázok. Presnejšie môže mať pridelené tri obrázky, pričom dva z nich sú alternatívou zvolené/nezvolené a tretí je obrázkom stavu položky. Obrázky môžeme položkám prideľovať dvoma spôsobmi, v závislosti na spôsobe vytvorenia položiek. Ak ich vytvárame v dobe návrhu programu, poslúži už spomínaný Editor položiek TTreeView. Ale samozrejme môžeme ich nastavovať i za behu programu. V oboch prípadoch však je potrebné prepojiť prvok TTreeView s prvkom TImageList, na čo slúžia vlastnosti Images a StateImages. V ukážke formulára na začiatku článku máte možnosť vivieť prvok TTreeView, ktorý má rôznofarebné obrázky položiek a nemá nastavený stavový obrázok.

../../_images/ttree_imglist.png

Ak teda chceme priradiť položkám obrázok, pripravíme si prvok TImageList a pridáme do neho nejaké obrázky, napríklad z adresára /usr/share/icons (pripomínam veľkosť 16 x 16 bodov). Aby náš prvok TTreeView mohol používať obrázky z tohoto zoznamu obrázkov, priradíme meno prvku TImageList do jeho vlastnosti Images. Poradie prvkov v TImageList je významné, pretože na obrázky sa odkazujeme pomocou ich indexu poradového čísla, pričom prvý obrázok má index 0.

To je všetko, čo potrebujeme nastaviť v prvku samotnom, zvyšok je už o nastavení každej položky, teda triedy TTreeNode. Táto ponúka na nastavenie obrázku položky dve vlastnosti: ImageIndex a SelectedIndex, do ktorých zadávame index (poradové číslo) obrázku v zozname obrázkov. ImageIndex obsahuje index obrázka, ktorý je zobrazený pri položke ak nie je vybratá a SelectedIndex zase obrázok, ktorý je zobrazený ak je položka vybratá (selected). Nastavením rôznych obrázkov možno zmeniť obrázok pri vybranej a nevybranej položke a nastavením rovnakých obrázkov sa obrázok pri výbere položky nezmení. Ak index týchto vlastností nastavíme na -1, znamená to, že položka nemá priradený obrázok.