====== Jednoduchý kreslící program - obdélník a elipsa ====== https://gitlab.fjfi.cvut.cz/culikzde/pw ===== Upravíme panel s nástroji ===== V našem oknu dosud máme **toolPanel** (typu Panel) a **pictureBox** (typu PictureBox). Přidáme z toolboxu //Panel// Nastavíme **BackColor** např. na modrou barvu, přejmenujeme na **colorPanel** (nastavíme vlastnost **(name)** na colorPanel). \\ Pannelů pro výběr barvy potřebujeme více, ale další kopie vytvoříme až programem. \\ Z vizuálního návrhu použijeme jako vzorpvou velikost prvního colorPanelu a vzdálenost od okraje toolPanelu. {{draw_tools.png}} Přidáme //ComboBox// * přejmenujeme na **comboBox** (jména nejsou příliš vynalézavá, alespoň odstaním 1 na konci jména) * nastavíme **DropDownStyle** na **DropDownList**, aby uživatel nemohl kolonku editovat a mohl jen vybírat z připravebých hodnot * nastavíme **Anchor** na **Top** a **Right**, při změné velikosti okna si comboBox bude udržovat původní vzdálenost od pravého okraje okolního panelu {{draw_anchor.png}} * nastavíme **Items** na line, rectangle a ellipse. Jednotlivé hodnoty zadáme na samostané řádky ( bez dalších oddělovačů, za poslední hodnotou NENÍ žádná prázdná řádka, jinak by vznikla jedna položka bez jména) {{draw_items.png}} Nastavit jako počáteční hodnotu na //line// musíme až jedním příkazem v konstruktoru. Zavedeme si __výčtový typ__ **Shape**. \\ A do comboBox.SelectedIndex uložíme konstantu pro čáru přetypovanou na int (nulu). \\ Hodnoty výčtivého typu se zapisují ve tvaru //jméno typu//, //tečka// a //jméno položky//, např. **Shape.ellipse**. \\ Přetypování se zapisuje jako v jazyce C, např. **(int) n**, ale toto přetypování kontroluje mnohem více situací než v jazyce C. ( Nebo si nadefinujeme tři celočíselné konstanty line, rectangle a ellipse. ) public partial class DrawForm : Form { private enum Shape { line, rectangle, ellipse }; // const int line = 0; // const int rectangle = 1; // const int ellipse = 2; public DrawForm () { InitializeComponent (); comboBox.SelectedIndex = (int) Shape.line; ===== Proměnné pro používanou barvu ===== Deklarujeme proměnnou **pen** typu **Pen** a v této "pracovní tužce" budeme uchovávat barvu pro kreslení čar a okrajů. Barvu pro vyplňování obrazců uložíme do proměnné **brushColor** typu **Color**. Pro vyplňování budeme používat "štětec" uložený v proměnné **brush** typu **Brush**. Proměnné //pen// a //brush// jsou objektového typu. \\ V C# jsou to odkazy (v C ukazatele). \\ ( V deklaraci typu nepoužíváme ** * ** jako v C. ) \\ ( Také nepoužíváme ** - > **, píšeme jen tečku. ) Ze základní třídy **Brush** je odvozeno několik tříd. My budeme používat **SolidBrush** pro jednobarevnou výplň. \\ Později použijeme výplně s barevnými přechody. K barvě štětce se již tak snadno nedostaneme, proto ji skladujeme v proměnné **brushColor**. Typ **Color** je deklarován jako **struct** (nikoliv **class** jako předešlé objektové typy.) \\ V C# **struct** znamená, že hodnoty (v našem případě typu Color) nejsou dostupné přes ukazatel (v C++ by to byl typ s "hvězdičkou" ** Color * ** ), \\ ale jsou uloženy přímo ve vícebytové proměnné (dle velikosti struktury) (v C++ by to byl typ "bez hvězdičky" ** Color ** ) public partial class DrawForm : Form { private Pen pen; private Brush brush; private Color brushColor; private enum Shape { line, rectangle, ellipse }; public DrawForm () { InitializeComponent (); pen = new Pen (Color.Red); brushColor = Color.Yellow; brush = new SolidBrush (brushColor); comboBox.SelectedIndex = (int)Shape.line; Proměnné pen a brush jsou na úrovni třídy a tak jsou automaticky inicializovány na **null**. \\ My do nich uložíme červenou tužku a žlutý štětec. **private**, **protected**, **public** platí jen pro následující deklaraci (až do sředníku) \\ ( Pokud neuvedene ani jedno klíčové slovo, pro třídy a struktury se použije private. ) Globální proměnné v C# nejsou povoleny. \\ Pro nás mají proměnné na úrovni třídy dobrou vlastnost, že pokud vytvoříme několik instancí okna, tak každé může používat svoji barvu. ===== Nakreslíme obdélník a elipsu ===== Vnitřek elipsy vyplňíme funkcí **FillEllipse**, okraj nakreslíme funkcí **DrawEllipse** g.FillEllipse (brush, X0, Y0, e.X - X0, e.Y - Y0); g.DrawEllipse (pen, X0, Y0, e.X - X0, e.Y - Y0); Proměnná **g** je **Graphics** pripojený na náš **pictureBox.Image** Prarametry jsou použitá tužka nebo štětec, \\ souřadnice levého horního roku opsanému obdélníku dané elipsy, \\ šířka a výška obdélníku. Pro záporné šířka a/nebo výšky se nakreslí elipsy, které uživatel nejspíše měl na mysli. \\ ( Stisknout myš, táhnout nahoru a/nebo vlevo a potom pustit myš. ) \\ ( Souřadná soustava obrázku má počátek v levém horním rohu a osa y míří dolů. ) V případě obdélníku funkce **FillRectangle** a **DrawRectangle** pro záporné výšky a šířky nic nenakreslí. \\ Musíme si počáteční X0,Y0 případně prohodit s koncovým e.X,e.Y \\ ( Nesmíme změnit původní X0 a Y0, budeme je potřebovat při kreslení dalšího náhledu na vznikající obdélník. ) Vše se odehrává v **pictureBox_MouseMove**. \\ Pokud je myš stisknuta obnovíme obraz na stav při stisku a podíváme se do **comboBox**u jakým nástrojem máme kreslit. private int X0, Y0; private bool press = false; private Image save; private void pictureBox_MouseDown (object sender, MouseEventArgs e) { X0 = e.X; Y0 = e.Y; press = true; save = new Bitmap (pictureBox.Image); } private void pictureBox_MouseMove (object sender, MouseEventArgs e) { if (press) { Graphics g = Graphics.FromImage (pictureBox.Image); g.DrawImage (save, 0, 0); Shape inx = (Shape) comboBox.SelectedIndex; if (inx == Shape.line) { g.DrawLine (pen, X0, Y0, e.X, e.Y); } else if (inx == Shape.rectangle) { int X1 = X0; int Y1 = Y0; int X2 = e.X; int Y2 = e.Y; if (X2 < X1) { int t = X1; X1 = X2; X2 = t; } if (Y2 < Y1) { int t = Y1; Y1 = Y2; Y2 = t; } g.FillRectangle (brush, X1, Y1, X2 - X1, Y2 - Y1); g.DrawRectangle (pen, X1, Y1, X2 - X1, Y2 - Y1); } else if (inx == Shape.ellipse) { g.FillEllipse (brush, X0, Y0, e.X - X0, e.Y - Y0); g.DrawEllipse (pen, X0, Y0, e.X - X0, e.Y - Y0); } pictureBox.Invalidate (); } } private void pictureBox_MouseUp (object sender, MouseEventArgs e) { press = false; } {{draw_ellipse.png}} [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob//3677f15e/Draw/DrawForm.cs|stav z tohoto okamžiku na gitlab]]