https://gitlab.fjfi.cvut.cz/culikzde/pw
Přejdeme do “design režimu” (záložka DrawFrom.cs [design] nebo Shift-F7)
Pokud se místo "design" okna ohlásí chyba jako např. DrawForm does not contain a definition for colorPanel_Paint, otevřte soubor DrawForm.Designer.cs (např. poklepáním na zprávu o chybě) a odstraňte řádku odkazující na colorPanel_Paint.
// odstraňte řádku odkazující na již vymazanou funkci (např. colorPanel_Paint) this.colorPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.colorPanel_Paint);
Chyba nejspíše vznikla tak, že jste v designu dvakrát "kliknuli" na barevný panel, vznikla funkce void colorPanel_Paint (...) { ... }, kterou jste asi vymazali, ale v DrawForm.Designer.cs zůstala reakce na kliknutí,
private void colorPanel_MouseDown (object sender, MouseEventArgs e) { }
private void colorPanel_MouseDown (object sender, MouseEventArgs e) { Panel panel = sender as Panel; // Panel panel = (Panel) sender; if (e.Button == MouseButtons.Left && Control.ModifierKeys != Keys.Shift) { pen = new Pen (panel.BackColor); } else if (e.Button == MouseButtons.Right) { brushColor = panel.BackColor; brush = new SolidBrush (brushColor); } else if (e.Button == MouseButtons.Middle || e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Shift) { colorDialog.Color = panel.BackColor; if (colorDialog.ShowDialog () == DialogResult.OK) { panel.BackColor = colorDialog.Color; pen = new Pen (panel.BackColor); } } }
Parametr sender obsahuje odkaz na prvek, který událost způsobil.
Nyní to může být pouze náš colorPanel, ale později přidáme další panely s jinými barvami.
A tak musíme zjistit na který panel bylo kliknuto.
Sender je typu object, z kterého jsou odvozené všechny další třídy v jazyce C#.
Proměnná typu object může obsahovat odkaz (ukazatel) na libovolný objekt.
Typ je příliš obecný, neumožňuje nám pracovat např. s barvou panelu.
Parametr musíme přetypovat, máme dva možné zápisy.
Panel p = (Panel) sender;
Přetypování (typ) výraz je co do zápisu podobné jazyku C,
tvoří ho jméno typu v kulatých závorkách a za ním přetypovávaný výraz, který v závorkch být nemusí.
Na rozdíl od jazyka C, pokud za běhu programu nejde výraz přetypovat na uvedený typ, vznikne výjimka.
Panel p = sender as Panel;
Přetypováví výraz as typ
pokud za běhu programu výraz nejde přetypovat na uvedený typ, je výsledkem null.
if (sender is Panel) { ... }
Relace výraz is typ
vrací true pokud lze výraz přetypovat.
Pokud bylo stisknuto levé tlačítlo myši, vezmeme současnou barvu panelu a vytvoříme “tužku” zadané barvy, odkaz na ni uložíme do proměnné pen
if (e.Button == MouseButtons.Left) { pen = new Pen (panel.BackColor); }
Při stisku pravého tlačítka barvu uložíme pro pozdější použití do proměnné brushColor a vytvoříme jednobarevný “štětec”.
else if (e.Button == MouseButtons.Right) { brushColor = panel.BackColor; brush = new SolidBrush (brushColor); }
Pokud stiskneme prostřední tlačítko (kolečko na myši) změníme barvu panelu.
K tomu použijeme již na začátku kapitoly připravený dialog pro výběr barvy.
Metoda ShowDialog nabídne uživateli okénko pro výběr barvy, výsledkem funkce je OK pokud si uzživatel vybral barvu.
Většinou se nedoboručuje funkce s vedlejším účinkem volat v podmínce if ( ),
ale při zobrazení dialogového okna to bývá tolerováno.
if (colorDialog.ShowDialog () == DialogResult.OK) { }
Barevný dialog inicializujeme na současnou barvu panelu.
Pokud si uživatel vybral barvu, změníme také barvu “tužky”, což uživatel nejsíše předpokládá.
else if (e.Button == MouseButtons.Middle) { colorDialog.Color = panel.BackColor; if (colorDialog.ShowDialog () == DialogResult.OK) { panel.BackColor = colorDialog.Color; pen = new Pen (panel.BackColor); } }
Pokud myš nemá prostřední tlačítko, můžeme použít Shift a levé tlačítko.
Vraťe se k zdrojovému kódu celé metody colorPanel_MouseDown a podívejte se na Control.ModifierKeys a Keys.Shift.
Přidáme NumericUpDown
Můžeme přidat Label
Dvojklikem na penWidthNumeric přídáme metodu
private void penWidthNumeric_ValueChanged (object sender, EventArgs e) { pen.Width = (int) penWidthNumeric.Value; }
Upravíme část programu ve funkci colorPanel_MouseDown
if (e.Button == MouseButtons.Left && Control.ModifierKeys != Keys.Shift) { pen = new Pen (panel.BackColor, (int) penWidthNumeric.Value); } ... else if (e.Button == MouseButtons.Middle || e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Shift) { ... pen = new Pen (panel.BackColor, (int) penWidthNumeric.Value); }
Pokud Vám nevyhovuje změna barvy tužky při změně barvy panelu, tak poslední přiřazení zakomentujte
Prvek NumericUpDown jako hodnotu může obsahovat i desetinná čísla, a proto musíme Value převédst na int.
Pro připomenutí počáteční červená tužka a žlutý štětec jsou přednastaveny v konstruktoru
pen = new Pen (Color.Red); brushColor = Color.Yellow; brush = new SolidBrush (brushColor);
Menu se umístí někam na nevhodné místo.
Zobrazíme si Document Outline a myší posuneme pořadí prvků.
(v hlavním menu Visual Studia View / Other windows / Document Outline nebo Ctrl+Alt+T)
Uvnitř okna DrawForm by mělo být pořadí prvků:
První by měl být hlavního prvek uprostřed okna, a až za ním další prvky směrem k okraji okna
V právě přidaném menu klikneme do políčka Type Here
Pod “File” menu opět nalezneme Type Here.
Vpravo od “File” opět nalezneme Type Here.
Pod “Edit” menu.
Ve vytvořeném menu “File” dvakrát klikneme na námi přidanou položku “Quit”, vznikne metoda quitMenuItem_Click
private void quitMenuItem_Click (object sender, EventArgs e) { Close (); }
Funkce Close je deklarována uvnitř třídy Form, ze které je naše třída DrawForm odvozena.
Volání Close () je ekvivalentní this.Close () a uzavře naše okno a v tomto případě skončí i celý program.
Dvakrát klikneme ve vytvořeném menu “Edit” na položku “add Color”
private void addColorMenuItem_Click (object sender, EventArgs e) { addColorPanel (Color.Orange); }
V konstruktoru také přidáme několik barevných panelů
public DrawForm () { InitializeComponent (); // modry panel jiz existuje addColorPanel (Color.Yellow); addColorPanel (Color.Red); addColorPanel (Color.Green); pen = new Pen (colorPanel.BackColor); // modra barva podle prvniho panelu brushColor = Color.Yellow; brush = new SolidBrush (brushColor); /* ... */ }
A zbývá napsat funkci addColorPanel, tu musíme napsat celou.
private int panelCnt = 1; void addColorPanel (Color c) { Panel p = new Panel (); // vytvorime novy panel p.BackColor = c; // novy panel umistime vpravo od soucasnych panelu p.Left = colorPanel.Left + panelCnt * (colorPanel.Width + colorPanel.Left); panelCnt++; p.Top = colorPanel.Top; // ze vzoroveho panelu zkopirujeme souradnici y a velikost p.Width = colorPanel.Width; p.Height = colorPanel.Height; p.MouseDown += colorPanel_MouseDown; // pridame reakci na stisknuti mysi p.Parent = toolPanel; // pridame do toolPanelu }
using System; using System.Drawing; using System.Windows.Forms; namespace Draw { public partial class DrawForm : Form { private Pen pen; private Brush brush; private Color brushColor; private enum Shape { line, rectangle, ellipse }; public DrawForm () { InitializeComponent (); // modry panel jiz existuje addColorPanel (Color.Yellow); addColorPanel (Color.Red); addColorPanel (Color.Green); pen = new Pen (colorPanel.BackColor); // modra barva podle prvniho panelu brushColor = Color.Yellow; brush = new SolidBrush (brushColor); comboBox.SelectedIndex = (int)Shape.line; 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 void quitMenuItem_Click (object sender, EventArgs e) { Close (); } private int panelCnt = 1; void addColorPanel (Color c) { Panel p = new Panel (); // vytvorime novy panel p.BackColor = c; // novy panel umistime vpravo od soucasnych panelu p.Left = colorPanel.Left + panelCnt * (colorPanel.Width + colorPanel.Left); panelCnt++; p.Top = colorPanel.Top; // ze vzoroveho panelu zkopirujeme souradnici y a velikost p.Width = colorPanel.Width; p.Height = colorPanel.Height; p.MouseDown += colorPanel_MouseDown; // pridame reakci na stisknuti mysi p.Parent = toolPanel; // pridame do toolPanelu } private void addColorMenuItem_Click (object sender, EventArgs e) { addColorPanel (Color.Orange); } private void colorPanel_MouseDown (object sender, MouseEventArgs e) { Panel panel = sender as Panel; // Panel panel = (Panel) sender; if (e.Button == MouseButtons.Left && Control.ModifierKeys != Keys.Shift) { pen = new Pen (panel.BackColor, (int) penWidthNumeric.Value); } else if (e.Button == MouseButtons.Right) { brushColor = panel.BackColor; brush = new SolidBrush (brushColor); } else if (e.Button == MouseButtons.Middle || e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Shift) { colorDialog.Color = panel.BackColor; if (colorDialog.ShowDialog () == DialogResult.OK) { panel.BackColor = colorDialog.Color; pen = new Pen (panel.BackColor, (int) penWidthNumeric.Value); } } } private void penWidthNumeric_ValueChanged (object sender, EventArgs e) { pen.Width = (int)penWidthNumeric.Value; } 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; } } }