Lekce 7 - Kreslení na Graphics v C# .NET
V předešlém cvičení, Řešené úlohy k 3.-6. lekci Windows Forms v C# .NET, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Již umíme vytvořit poměrně sofistikované aplikace. Dnešní C# .NET tutoriál budeme věnovat kreslení.
Kreslení na Graphics
Vytvoříme aplikaci, která má za úkol zastřešit prodej vstupenek do
kina. Jak víme, v sálu je mnoho sedadel a pracovník kina by měl v aplikaci
vidět, která sedadla jsou již obsazená. Možná by vás napadlo naklikat pro
sedadla PictureBoxy. Pokud by však kino mělo 15 řad a každá
řada 30 sedadel, máme to 450 PictureBoxů. Asi tušíte, že
existuje lepší cesta, než začít bušit PictureBox1,
PictureBox2... A jak by se potom obsluhovaly? V případě, že
potřebujeme vykreslit něco náročnějšího, než jen jeden nebo dva
obrázky, využijeme Graphics. To spočívá v tom, že na
formulář umístíme jeden PictureBox a na jeho
plátno budeme vykreslovat to, co potřebujeme.
Aplikaci značně zjednodušíme, není třeba aby byla složitá. Bude umět zobrazit jen jeden sál, který bude zpočátku prázdný. Uživatel nakliká myší obsazená sedadla a poté stiskne tlačítko Uložit, které do zvolené lokace uloží jednoduchý txt soubor s informací o obsazenosti sálu. Ukládání si zkusíme proto, abychom se naučili pracovat s dialogy.
Návrh formuláře
Vytvořte si novou Windows Forms Aplikaci, formulář přejmenujeme na
KinoForm, záhlaví třeba na Evidence kinosálu.
Přes většinu formuláře natáhněte PictureBox, který
pojmenujeme kinoPictureBox. Pod PictureBox přijde
Button se jménem ulozitButton a textem
Uložit. Konečně na formulář přetáhněme i
SaveFileDialog. Ten se nepřidá přímo na formulář, ale do
lišty pod něj. Nejedná se totiž o formulářový prvek, ale pouze o pomocnou
komponentu. Přejmenujeme ji na kinoSaveFileDialog. Můžete si
pohrát s kotvami a podobně. Váš formulář by měl vypadat asi takto:

Logická vrstva
Asi vás nepřekvapí, že k aplikaci přidáme třídu Kinosal.
Bude mít jeden privátní atribut, kterým bude dvourozměrné pole
sedadel. Pokud jste s 2D polem ještě nepracovali, tak si ho můžete
představit jako tabulku. Jednorozměrné (klasické) pole je vlastně jen jeden
řádek. S 2D polem poté pracujeme úplně stejně, jako s jednorozměrným,
jen musíme uvést dvě souřadnice (X a Y). V mnoha jazycích se dělá 2D pole
jako pole polí, C# umí definovat přímo 2d pole a to takto:
class Kinosal { private bool[,] sedadla = new bool[30, 15]; }
Sedadla jsou typu bool, protože nás zajímá jen jestli je
volné nebo obsazené. 30 je šířka pole, 15 jeho
výška.
Do třídy ještě přidáme 2 privátní konstanty, jedna udává velikost vykreslovaného sedadla v pixelech a druhá mezeru mezi sedadly v pixelech. Zvykněte si konstanty používat, až budete chtít sedadla zvětšit, stačí pouze přepsat jednu konstantu a nemusíte luštit vykreslovací kód.
private const int velikost = 16; private const int mezera = 2;
Můžeme přejít k metodám.
Vykreslení
Kinosál by se měl umět vykreslit. Již jsme si zmínili, že budeme
kreslit na plátno. Toto plátno je typu Graphics a necháme si ho
přijít v parametru metody Vykresli(). Pro typ
Graphics je třeba přidat using System.Drawing, ale
to vás jistě nezaskočilo. Na plátno se potom kreslí pomocí jeho metod.
Nás bude zatím zajímat jen metoda FillRectangle(), která
vykreslí obdélník, vyplněný určitou barvou. Metod je tam obrovská spousta
pro různé geometrické tvary, ať už vyplněné nebo nevyplněné. Můžete
si je projet, některé si vyzkoušíme ještě v dalších lekcích.
V Graphics rozeznáváme dva typy barvy - barva výplně
(Brush = štětec) a barva obrysu (Pen = pero). Pro
vyplněný obdélník musíme zadat nějaký Brush. Hotové
instance nastavené na určité barvy nalezneme na statické třídě
Brushes (nebo pro obrysy Pens), stačí si jen vybrat.
Štětce mohou kreslit i nějakými vzory nebo obrázky, ale to pro nás není
důležité.
Pomocí dvou vnořených cyklů projedeme všechna sedadla v poli a na
plátno vykreslíme buď zelený nebo červený čtverec. Vnějším cyklem
budeme projíždět řádky, vnitřním sloupce v aktuálním řádku. Barvu
(přesněji štětec) určíme podle toho, zda je sedadlo na dané souřadnici
true nebo false. Kód metody bude následující:
public void Vykresli(Graphics g) { Brush brush; for (int j = 0; j < sedadla.GetLength(1); j++) { for (int i = 0; i < sedadla.GetLength(0); i++) { if (sedadla[i, j]) brush = Brushes.Red; else brush = Brushes.Green; g.FillRectangle(brush, i * (velikost + mezera), j * (velikost + mezera), velikost, velikost); } } }
Všimněte si, že v cyklech nepoužíváme hodnoty
30 a 15, ale používáme metodu
GetLength() s parametry 0 a 1. Tato
metoda slouží pro získání velikosti dvourozměrného pole. 0
je šířka, 1 je výška (samozřejmě záleží na nás, kterou
dimenzi si určíme jako výšku a kterou jako šířku). Pevnou velikost
neuvádíme pochopitelně z důvodu, že v budoucnu můžeme pole
zvětšit/zmenšit a museli bychom v kódu hledat kde všude jsme hodnoty
30 a 15 použili. Těmto problémům je vždy lepší
se vyhnout a pracovat s délkou pole.
Za zmínku stojí i samotné vykreslení obdélníku. Prvním parametrem
metody FillRectangle() je Brush, určující barvu
výplně. Další dva parametry jsou souřadnice levého horního rohu
obdélníku. Poslední dva parametry určují jeho výšku a šířku. Jelikož
je každé sedadlo široké 16 pixelů + 2 pixely mezera, musíme jeho
souřadnici touho hodnotou pronásobit. Pokud je v i např. hodnota
2 (kreslíme tedy 3. sloupec), kreslíme na X souřadnici
36, nikoli na 2
To samé platí pro souřadnici
Y.
Později si můžete zkusit nahradit FillRectangle() metodou
FillOval(). Funguje úplně stejně, ale vykreslí elipsu. Určitě
si po dokončení aplikace zkuste vykreslit i další tvary.
Propojení formuláře s logickou vrstvou
Základ logiky máme hotový, pojďme ji propojit s formulářem. Přejdeme do kódu formuláře a ve třídě vytvoříme privátní instanci kinosálu:
private Kinosal kinosal = new Kinosal();
Nyní naklikneme PictureBoxu událost Paint.
Musíte to udělat přes ikonu blesku v oknu Properties. Událost volá systém
ve chvíli, kdy se má okno překreslit. To je samozřejmě v případě
spuštění aplikace, ale také po obnovení z minimalizace, ve chvíli, kdy po
okně aplikace přejedeme jiným oknem a podobně.
V obslužné metodě události zavoláme na instanci kinosálu metodu
Vykresli(). Plátno nám přijde jako vlastnost parametru
události. Pouze ho předáme dále metodě logiky, která nám na něj
vykreslí.
private void kinoPictureBox_Paint(object sender, PaintEventArgs e) { kinosal.Vykresli(e.Graphics); }
Za výsledek se nemusíme stydět:

V příští lekci, Zpracování kliknutí na souřadnice v C# .NET, si ukážeme, jak kliknutím na určité sedadlo změnit jeho stav a zprovozníme také ukládání. Projekt máte jako vždy ke stažení v příloze pro případ, že se vám něco nepodařilo.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 1196x (50.2 kB)
Aplikace je včetně zdrojových kódů v jazyce C#


David se informační technologie naučil na