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.
Přidáme ComboBox
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;
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.
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 comboBoxu 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; }