Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 11 - Kreslení na Canvas v C# .NET WPF

V předešlém cvičení, Řešené úlohy k 6.-10. lekci WPF v C# .NET, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V dnešním tutoriálu se naučíme kreslit geometrické tvary Rectangle pomocí Canvas v C# .NET WPF. Začneme aplikaci k evidenci volných a obsazených sedadel v kině.

Kreslení na Canvas

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á. Mohlo by nás napadnout naklikat pro jednotlivá sedadla prvek Button. Pokud by však kino mělo 15 řad a každá řada 30 sedadel, máme to 450 prvků Button. Existuje lepší cesta, než začít bušit prvky Button1, Button2... 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 prvek Canvas, česky plátno. To spočívá v tom, že na formulář umístíme pouze jeden Canvas a do něj budeme vykreslovat to, co potřebujeme.

Aplikaci značně zjednodušíme. 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řme si novou WPF Aplikaci. Titulek okna nastavme na Evidence kinosálu. Oknu nastavíme vlastnost WindowStartupLocation na hodnotu CenterScreen. Tím zajistíme, že se okno při spuštění aplikace zobrazí ve středu obrazovky.

Pro návrh formuláře využijeme z předešlých lekcí již jistě dobře známý prvek Grid. Vzhled aplikace není nikterak složitý, a tak si mřížku rozdělíme na dva řádky. Jeden řádek bude obsahovat prvek Canvas a ve druhém bude prvek Button s textem Uložit. U tlačítka si ještě přidáme událost Click a necháme si vygenerovat metodu v Code Behind, která se vždy zavolá, když uživatel na tlačítko klikne. Náš formulář by měl vypadat asi takto:

formulář aplikace evidence kinosálu - WPF - Okenní aplikace v C# .NET

A zde je jeho odpovídající XAML kód:

<Window x:Class="Kino.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-;;compatibility/2006"
        xmlns:local="clr-namespace:Kino"
        mc:Ignorable="d"
        Title="Evidence kinosálu" WindowStartupLocation="CenterScreen" Height="450" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="350"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Canvas Name="MyCanvas" Margin="20 50 0 0"></Canvas>
        <Button Name="Ulozit" Content="Uložit" Grid.Row="1" Height="20" Width="100" Click="Ulozit_Click"></Button>
    </Grid>
</Window>

Logická vrstva

K aplikaci přidáme třídu Kinosal. Bude mít jeden privátní atribut, kterým bude dvourozměrné pole sedadel.

Dvourozměrné pole jsme probírali v lekci Vícerozměrná pole v C# .NET.

2D pole si můžeme 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 readonly 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:

...
private const int velikost = 16;
private const int mezera = 2;

Jedna udává velikost vykreslovaného sedadla v pixelech a druhá mezeru mezi sedadly v pixelech. Zvykněme si konstanty používat. Až budeme chtít sedadla zvětšit, stačí pouze přepsat jednu konstantu a nemusíme luštit vykreslovací kód.

Můžeme přejít k metodám.

Vložení obdélníků

Již jsme si zmínili, že budeme kreslit na plátno. Jednotlivé obdélníky reprezentující sedadla budou jako objekty, které na plátno vložíme pomocí metody VlozObdelniky(). Toto plátno je typu Canvas, které bude vstupním parametrem metody.

Je potřeba přidat jmenný prostor using System.Windows.Shapes, který nám zpřístupní třídu Rectangle (obdélník). Když budeme jednotlivé obdélníky vkládat na prvek Canvas, tak jim vždy nastavíme šířku a výšku na konstantu velikost. Dále nastavíme příslušnou barvu ve vlastnosti Fill pomocí statické třídy Brushes, která obsahuje hotové instance barev.

Visual Studio automaticky generuje jmenné prostory. V naší aplikaci vygeneruje jmenný prostor using System.Windows.Drawing, který je nutné pro správnou funkci aplikace smazat.

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:

...
public void VlozObdelniky(Canvas MyCanvas)
{
   for (int j = 0; j < sedadla.GetLength(1); j++)
   {
      for (int i = 0; i < sedadla.GetLength(0); i++)
      {
          Rectangle rectangle = new Rectangle
          {
              Height = velikost,
              Width = velikost,
          };

              rectangle.Fill = sedadla[i, j] ? Brushes.Red : Brushes.Green;
              MyCanvas.Children.Add(rectangle);

              Canvas.SetLeft(rectangle, i * (velikost + mezera));
              Canvas.SetTop(rectangle, j * (velikost + mezera));
       }
    }
}

Všimněme 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. Můžeme vidět, že vykreslení probíhá tak, že se každá instance třídy Rectangle přidá jako potomek do našeho prvku Canvas. Aby se obdélníky zobrazily přesně tam, kde chceme, tak musíme ještě nastavit jejich pozici. Využijeme statickou třídu Canvas, která obsahuje metody SetLeft() a SetTop(), které představují souřadnice levého horního rohu obdélní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.

Propojení formuláře s logickou vrstvou

Základ logiky máme hotový, pojďme ji propojit s formulářem. Přejdeme do Code Behind formuláře a vytvoříme privátní instanci kinosálu s modifikací readonly:

readonly Kinosal kinosal = new Kinosal();

Nyní už je to opravdu velmi jednoduché. Na instanci kinosálu zavoláme metodu VlozObdelniky() a jako parametr jí předáme náš Canvas, který jsme si definovali ve formuláři XAML. Aby došlo k vykreslení při startu aplikace, tak tento kód umístíme v Code Behind do konstruktoru formuláře:

...
public MainWindow()
{
    InitializeComponent();
    kinosal.VlozObdelniky(MyCanvas);
}
...

Testování

Po spuštění aplikace uvídíme tento výsledek:

formulář aplikace evidence kinosálu canvas - WPF - Okenní aplikace v C# .NET

V příští lekci, Zpracování kliknutí na obdélník v C# .NET WPF, 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? Zdrojový kód vzorové aplikace je ke stažení každých pár lekcí. Zatím pokračuj dál, a pak si svou aplikaci porovnej se vzorem a snadno oprav.

Předchozí článek
Řešené úlohy k 6.-10. lekci WPF v C# .NET
Všechny články v sekci
WPF - Okenní aplikace v C# .NET
Přeskočit článek
(nedoporučujeme)
Zpracování kliknutí na obdélník v C# .NET WPF
Článek pro vás napsal Radek Němec
Avatar
Uživatelské hodnocení:
40 hlasů
Autor začínal programovat v jazyce C# a během vysoké školy se naučil další programovací jazyky. Pracoval jsem jako programátor mobilních aplikací na platformě iOS a nyní jsem se opět vrátil k C# a zajímám se o webové technologie v ASP.NET Core.
Aktivity