====== Jednoduchý kreslící program ====== https://gitlab.fjfi.cvut.cz/culikzde/pw Opět vytvoříme nový projekt Menu File / New / Project \\ Vybereme typ projektu ** Windows Forms App (.NET Framework) C# ** \\ Projekt nazveme **Draw** Z **toolboxu**, ze skupiny **Containers**, přidáme **Panel** * v **Properties** nastavíme **(name)** na **toolPanel** (s malým písmenem na začátku) * **Dock** nastavíme na **Top**, panel se umístí k hornímu okraji okna * můžeme **BorderStyle** nastavit na **FixedSingle**, aby okraje panelu byly vidět Z **toolboxu**, ze skupiny **Common**, přidáme **PictureBox** * nastavíme **(name)** na **pictureBox** (s malým písmenem na začátku, PictureBox s velkým písmenem je jméno třídy) * **Dock** nastavíme na **Fill**, box zaplní vnitřek okna {{draw_dock.png}} V **Solution Exploreru** pravou myší klikneme na původní **Form1.cs**, z kontextového menu vybereme **Rename** a \\ přejmenujeme na **DrawForm** (podívejte se na zelený obdélníček na následujícím obrázku) Zkontrolujeme, zda pictureBox nepřekrývá toolPanel (zkontrolujte roh označený žlutým kroužkem) Pokud překrývá, v hlavním menu **View / Other windows / Document Outline** nebo **Ctrl+Alt+T** \\ Na levé záložce Document Outline, posuneme myší **pictureBox** nad **toolPanel** {{draw_setup.png}} Klikneme na **pictureBox**, \\ v **Properties** přepneme na **Events** (tlačítko s bleskem), \\ a dvakrát klikneme do prázdného políčka vpravo od **MouseDown**, \\ zobrazí se nám metoda **pictureBox_mouseDown**. private void pictureBox_MouseDown(object sender, MouseEventArgs e) { } :!: Hlavičku metody sami nepište, vždy "naklikejte", chyběla by vazba v DrawForm.designer.cs. Doplníme několik příkazů: public DrawForm () { InitializeComponent (); pictureBox.Image = new Bitmap (800, 600); } private void pictureBox_MouseDown(object sender, MouseEventArgs e) { Graphics g = Graphics.FromImage (pictureBox.Image); Pen pen = new Pen (Color.Red); g.DrawLine (pen, 0, 0, e.X, e.Y); pictureBox.Invalidate (); } pictureBox je jen "rámeček" držící vlastní obrázek v pictureBox.Image \\ V konstruktoru sem umístíme novou "Bitmapu" - obddélníkové pole barevných bodů pictureBox.Image = new Bitmap (800, 600); Při stisku myši na chvilku vytvoříme objekt typu **Graphics**, s jehož pomocí budeme kreslit do bitmapy. \\ ( Na konci funkce, zanikne lokální proměnná **g** a na objekt typu Graphics jižnepovede ukazatel a objekt zanikne. ) Připravíme si červenou "tužku" na následující kreslení. Nakreslíme červenou čáru z levého horního rohu **0,0** na místo stisku myši **e.X,e.Y** Funkcí Invalidate upozorníme Windows, že mají překreslit náš pictureBox Graphics g = Graphics.FromImage (pictureBox.Image); Pen pen = new Pen (Color.Red); g.DrawLine (pen, 0, 0, e.X, e.Y); pictureBox.Invalidate (); [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/abbb7d21d13dd7c58539d1283364352a3f42444c/Draw/DrawForm.cs|na gitlab.fjfi.cvut.cz naleznete zdrojový text právě z tohoto okamžiku]] ===== Kreslíme úsečku ====== Nyní chceme nakreslit úsečku od místa stisknutí myši až po místo, kde myš uvolníme. Připravíme si proměnné X0 a Y0 pro uložení souřadnice kde byla myš stisknuta. \\ Proměnné nebudou lokální, ale budou na úrovni třídy DrawForm, aby existovaly mezi jednotlivými voláními funkcí pictureBox_mouseDown a pictureBox_mouseUp pictureBoxu přidáme ("naklikáme") událost **MouseUp** public partial class DrawForm : Form { public DrawForm () { InitializeComponent (); pictureBox.Image = new Bitmap (800, 600); } private int X0, Y0; private void pictureBox_MouseDown(object sender, MouseEventArgs e) { X0 = e.X; Y0 = e.Y; } private void pictureBox_MouseUp (object sender, MouseEventArgs e) { Graphics g = Graphics.FromImage (pictureBox.Image); Pen pen = new Pen (Color.Red); g.DrawLine (pen, X0, Y0, e.X, e.Y); pictureBox.Invalidate (); } } Úsečka se zobrazí, až uvolníme myš. [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/7a1ce54f1248b20be5c0ff31d8dc9622c16775a6/Draw/DrawForm.cs|stav na gitlabu]] ===== Náhled právě kreslené úsečky ====== Pokusíme se při každém pohybu myši zobrazit náhled na právě kreslenou úsečku Přidáme proměnnou **press** obsahující **true**, pokud je myš stále ještě stisknuta. Kreslení přesuneme do pictureBox_MouseMove pictureBoxu přidáme ("naklikáme") událost **mouseUp** private int X0, Y0; private bool press = false; private void pictureBox_MouseDown(object sender, MouseEventArgs e) { X0 = e.X; Y0 = e.Y; press = true; } private void pictureBox_MouseMove (object sender, MouseEventArgs e) { if (press) { Graphics g = Graphics.FromImage (pictureBox.Image); Pen pen = new Pen (Color.Red); g.DrawLine (pen, X0, Y0, e.X, e.Y); pictureBox.Invalidate (); } } private void pictureBox_MouseUp (object sender, MouseEventArgs e) { press = false; } Program náhledy úseček kreslí, ale nemaže. {{draw_multi.png}} Můžete si také zkusit co se stane, když vynecháme **if (press)** nebo **press = false** [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/09ddeb6388d05a45f16dff65587750a68a6d8498/Draw/DrawForm.cs|gitlab]] ===== Vytvoříme bitmapu správné velikosti ====== V kostruktoru vytvoříme bitmapu stejné velikosti jako je náš pictureBox. \\ A bitmapu vyplníme bílými body. Dosud obsahovala __průhledné__ body. public DrawForm () { InitializeComponent (); int w = pictureBox.Width; int h = pictureBox.Height; Bitmap b = new Bitmap (w, h); Graphics g = Graphics.FromImage (b); Brush br = new SolidBrush (Color.White); g.FillRectangle (br, 0, 0, w, h); pictureBox.Image = b; } Pro vyplnění plochy si připravíme bílý štětec a \\ nakreslíme obdélník od (0,0) do (w-1,h-1), ale parametry zadáme (0, 0, w, h) g.FillRectangle (br, 0, 0, w, h); pictureBox.Image = b; Na konci konstruktoru právě vytvořenou bitmapu uložíme do pictureBox.image \\ Funkce Invalidate zde není potřeba, protože se změnil celý "image" ===== Uložíme obraz před stiskem myši ====== Vždy při stisku myši uložíme původní obraz a před kreslením úsečky původní obraz obnovíme V proměnné **save** bude odkaz (ukazatel) na objekt typu Image s původním obrázkem. private Image save; Při stisku myši vytvoříme nový objekt typu Bitmap a v jeho konstruktoru do něj zkopírujeme současný obrázek. \\ (Třída Bitmap je odvozena z třídy Image.) V jazyce C# jsou proměnné objektových typů odkazy, ale hvězdičky a šipky (->) jako v C++ se nepoužívají. save = new Bitmap (pictureBox.Image); Před nakreslením úsečky zkopírujeme ("obtiskneme") schovaný obrázek na souřadnici 0,0. g.DrawImage (save, 0, 0); Pokud by v uschovaném obraze byly průhledné body, tak by se odpovídající body na obrazovce nezněnily. public partial class DrawForm : Form { public DrawForm () { InitializeComponent (); int w = pictureBox.Width; int h = pictureBox.Height; Bitmap b = new Bitmap (w, h); Graphics g = Graphics.FromImage (b); Brush br = new SolidBrush (Color.White); g.FillRectangle (br, 0, 0, w, h); pictureBox.Image = b; } 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); Pen pen = new Pen (Color.Red); g.DrawLine (pen, X0, Y0, e.X, e.Y); pictureBox.Invalidate (); } } private void pictureBox_MouseUp (object sender, MouseEventArgs e) { press = false; } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/d8e377d91fa41a7627917cab133f0fbad0d7cdd0/Draw/DrawForm.cs|stav z tohoto okamžiku na gitlab]]