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 PictureBox
y. 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 PictureBox
u 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 1193x (50.2 kB)
Aplikace je včetně zdrojových kódů v jazyce C#