Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 182. – dokončení StringGridu

Jan Šindelář 28.4.2005

Dnes nás čeká dokončení příkladu z minulého dílu. Slíbili jsme si přidat do buněk StringGridu tlačítka a jako bonus nás ještě čeká zobrazování šipek v hlavičce tabulky jako indikátorů setříděnosti tabulky dle daného sloupce.

Tentokrát budeme více povídat a méně ukazovat kód, resp. kód je docela dlouhý a nemělo by velký význam zbytečně plýtvat místem v článku. Proto bude nejlepší, když si rovnou stáhnete a otevřete ukázkový projekt (odkaz doufám naleznete na konci článku) a budete sledovat a studovat jednotlivé funkce tak, jak o nich bude postupně řeč.

Dnes pomocné objekty

Co přesně bude cílem našeho dnešního snažení? Z minula máme hotovou hlavičku, která je již zobrazena pevně i v případě prázdné tabulky. Dnes si ukážeme, že na jednotlivých řádcích (resp. uvnitř buněk tabulky) nemusí být je obyčejný text, ale umístíme si do buněk i pomocné objekty jako jsou zatržítka, radiobuttony a tlačítka a samozřejmě budeme schopni detekovat, zda na ně uživatel kliknul myší.

Druhým dnešním úkolem bude drobně vylepšit hlavičku tabulky. Při zobrazování dat v tabulce bývá nepsaným pravidlem to, že klikne-li uživatel na hlavičku konkrétního sloupce, bude tabulka podle něj setříděna a to střídavě vzestupně či sestupně. Jako indikátor toho, podle kterého sloupce je zrovna tabulka setříděna a navíc jakým "směrem", se používá nějaký obrázek či ikona obvykle v podobě šipky, která je zobrazena v hlavičce inkriminovaného sloupce. Právě o tuto možnost si vylepšíme i naší tabulku.

Kreslíme

Pustíme se tedy do práce. Oproti minulému dílu si nepovíme v zásadě nic nového. Opět budeme kreslit buňky sami, takže hlavní část kódu se nachází v události OnDrawCell naší tabulky. Nejprve si však musíme připravit ještě jednu funkci s názvem GetBtnRect. Ta nám poslouží k přesnému zjištění souřadnic budoucích tlačítek (či jiných objektů v buňkách) dle zadaného aktuálního řádku a sloupce tabulky.

I když vypadá komplikovaně, nejedná se o nic jiného než o vypočítání pozice podle velikosti buňky, velikosti tlačítka (definováno konstantou) a zarovnání tlačítka v buňce. Pro každý ze stylů zarovnání se tak dostaneme prakticky ke čtyřem jednoduchým výpočtům na úrovni sčítání a odčítání souřadnic.

Použitím parametru Complete ještě můžeme určit, zda nás zajímá kompletní plocha vymezená pro tlačítko (ne vždy využitá) a nebo čistě jen souřadnice obdélníku, kde bude vykreslen. Vše lépe pochopíte ze zdrojového kódu a až bude příklad kompletní, rovněž z vašeho experimentování s nastavením různých parametrů a rozměrů. Voláním této funkce tedy získáme po zadaní souřadnic buňky a požadovaného zarovnání přesné souřadnice budoucího tlačítka.

Když už víme, kam budeme tlačítka kreslit, můžeme se vrátit k události OnDrawCell naší tabulky, ve které všechno kreslení probíhá. Nejprve zjistíme, zda kreslíme hlavičku tabulky a nebo běžný řádek. Pro první případ použijeme kód z minulého dílu, druhá část větvení nás čeká teď. Zjistíme polohu budoucího textu buněk a to na základě sloupce, ve kterém se momentálně nacházíme. V našem příkladu bude v prvním sloupci (s indexem nula) zatržítko zarovnané vlevo a vpravo od něj text. Druhý sloupec bude standardní a ve třetím sloupci bude tlačítko tentokrát vpravo od textu. Poslední sloupec je opět standardní.

Následuje krok, kde vybereme barvy. Kurzorem označený řádek tabulky bude zobrazen inverzně, resp. bude mít modré pozadí a červený text. Ostatní neoznačené řádky buňky budou mít barvu standardní dle barevného schématu Windows, který je použit (tedy nejčastěji černé písmo a bílé pozadí).

Dalším krokem je vykreslení textu. Pro jednoduchost se do buněk vypisují jejich souřadnice, přičemž pro vykreslení je použita funkce DrawText (kliknutím na odkaz se dostanete na stránky MSDN s podrobným popisem) stejně jako v minulém dílu.

A konečně se dostáváme ke kreslení zatržítek a tlačítek. Už jsme si řekli, že v prvním sloupci (opět připomínám, že má index nula) chceme nakreslit zatržítko, ve třetím sloupci (index dvě) pak tlačítko. Zatímco tlačítko si vykreslíme téměř "ručně" pomocí funkce DrawEdge, k vykreslení zatržítka můžeme použít funkci DrawFrameControl, kde nám stačí specifikovat typ objektu, který chceme nakreslit. Na výběr máme mezi několika možnostmi, přičemž pro náš příklad jsme použili zatržítko a radiobutton, které střídáme po jednotlivých řádcích.

Spouštíme projekt

A tím máme vlastně kreslení hotovo a projekt můžeme směle spustit. Zatím je však poměrně "mrtvý", chybí mu interakce s uživatelem, tedy zejména detekce toho, které tlačítko či zatržítko bylo aktivováno. K tomu použijeme standardní událost OnClick našeho StringGridu. Pomocí dostupných funkcí převedeme souřadnice kurzoru na souřadnice tabulky a snadno zjistíme, ve které buňce se momentálně nacházíme a zda jsme kliknuli na některé tlačítko či jiný objekt.

Zbývá poslední věc a tou jsou zmiňované šipky při kliknutí na hlavičky sloupců tabulky. Jelikož buňky v režimu fixed nereagují na událost OnClick, musíme použít událost OnMouseDown a obdobným způsobem jako v předchozím případě zjistíme příslušné souřadnice daného sloupce. O samotné vykreslení se postará opět kód v proceduře OnDrawCell.

A tím je náš příklad definitivně hotov. Teď už se můžete pustit do experimentů. Velmi záhy zjistíte, že není problém příklad upravit a kreslit téměř libovolný objekt do libovolné buňky. Určitě vás však také zklame, že zatržítko ani radiobutton (byť vykreslené pomocí API a ne ručně jako "simulace") se nechovají tak jak jsme zvyklí, ale spíše jen jako "obrázky" těchto objektů. Je to tak, o jejich dynamičnost a reagování podle toho, jak uživatel kliká, se musíme bohužel postarat sami, ale uchovávat a překreslovat stavy jednotlivých objektů není zase takový problém.

Naše dnešní povídání bylo poměrně rozsáhlé a bylo nutné vidět zdrojový kód před sebou, ale přesto věřím, že jste se dobře zorientovali. Připomínám ještě sekci private ve zdrojovém kódu, kde se nachází několik pomocných proměnných, které jsem pro zjednodušení povídání vynechal, ale jejichž funkce je zřejmá z jejich názvu i použití. Poslední věcí, kterou nesmíte nepodcenit, je nastavení vlastností samotného StringGridu v Object Inspectoru.

Pokud jste se pustili do tvorby vlastního projektu a zdrojový kód našeho příkladu máte jen jako vzor, možná jste zjistili, že vám vše nefunguje úplně přesně jak má. Doporučuji proto detailně prostudovat nastavení StringGridu v naší ukázce (proto je ostatně dostupný celý projekt, ne jen zdrojový kód jednotky). Důležité je zejména správné nastavení parametrů v Options a nulová tloušťka ohraničení buněk. Jinak se může stát, že se nebude vše překreslovat tak, jak by mělo.

A to už je opravdu vše. Slíbený ukázkový projekt stahujte zde.

Zdroj: Vegar Vikan