====== 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]]