====== Jednoduchý kreslící program - dialog s parametry barevné výplně ====== https://gitlab.fjfi.cvut.cz/culikzde/pw ===== BrushManipulator ===== Vytvoříme pomocnou třídu, kterou zobrazíme v propertyGridu V **Solution Exploreru** pravou myší klikneme na //projekt Draw// \\ Z kontextového menu vybereme **Add**, **Class** \\ Soubor pojmenujeme **BrushManipulator.cs** Před **class** připíšeme **public**, aby třída byla dostupná i z jiných jmenných prostorů Deklarujeme **vlastnost** Color1 public Color Color1 { get; set; } * Není to proměnná v deklaraci jsou navíc { } * Není to funkce v deklaraci nejsou ( ) * Vlastnost (property) představuje dvojici funkcí pro čtení a zápis hodnoty, ale v programu s ní pracujeme jako s porměnnou * Nejjednodušší implemenace { get; set; } vytvoří skrytou proměnnou a dvě funkce pro čtení a změmu proměnné * PropertyGrid zobrazuje právě vlastnosti, proto vlastnost programujeme [Category ("Colors")] [DisplayName ("FirstColor")] [Description ("First Color ...")] public Color Color1 { get; set; } Vlastnosti můžeme přidat **attributy**, které překladač uloží spolu s dalšími typovými informacemi do přeloženého programu. \\ Attributy se vztahují k dané deklaraci (může to být i deklarace proměnné, funkce nebo třídy Category ovlivní rozdělení vlastností do skupin v PropertyGrid \\ DisplayName nahradí identikátor Color1 ve vzniklé tabulce Podobně přidáme **Color2** a celočíselné vlastnosti **X1**, **Y1**, **X2** a **Y2**, Doplníme konstruktor s dvěmi barvami zadanými jako parametry public BrushManipulator (Color first, Color second) { ... } A funkci **createBrush**, která ze zdadaných vlastností vytvoří štětec public LinearGradientBrush createBrush () { return new LinearGradientBrush (new PointF (X1, Y1), new PointF (X2, Y2), Color1, Color2); } Celá třída BrushManipulator using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; namespace Draw { public class BrushManipulator { public BrushManipulator (Color first, Color second) { Color1 = first; Color2 = second; X1 = 0; Y1 = 0; X2 = 100; Y2 = 100; } public LinearGradientBrush createBrush () { return new LinearGradientBrush (new PointF (X1, Y1), new PointF (X2, Y2), Color1, Color2); } [Category ("Colors")] [DisplayName ("FirstColor")] [Description ("First Color ...")] public Color Color1 { get; set; } [Category ("Colors")] [DisplayName ("SecondColor")] [Description ("Second Color ...")] public Color Color2 { get; set; } [Category ("From")] public int X1 { get; set; } [Category ("From")] public int Y1 { get; set; } [Category ("To")] public int X2 { get; set; } [Category ("To")] public int Y2 { get; set; } } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/master/Draw/BrushManipulator.cs|BrushManipulator.cs]] ===== Úpravy hlavního okna DrawForm ===== Proměnné brush a brushColor nahradíme proměnnou **manipulator** private BrushManipulator manipulator; V konstruktoru manipulator vytvoříme pen = new Pen (colorTools[0].BackColor); // modra barva podle prvniho panelu manipulator = new BrushManipulator (colorTools[1].BackColor, // zluta podle druheho panelu colorTools[2].BackColor); // cervena podle tretiho panelu V metodě **pictureBox_MouseMove** pomocí manipulátoru vytvoříme štětec a uložíme ho do lokální proměnné private void pictureBox_MouseMove (object sender, MouseEventArgs e) { if (press) { Graphics g = Graphics.FromImage (pictureBox.Image); g.DrawImage (save, 0, 0); Brush brush = manipulator.createBrush (); Ve funkci **colorPanel_MouseDown**, pokud klikneme pravou myší na barevný panel, změníme obě barvy manipulátoru na stejnou barvu. 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.Color = panel.BackColor; refreshPen (); } else if (e.Button == MouseButtons.Right) { manipulator.Color1 = panel.BackColor; manipulator.Color2 = panel.BackColor; // !? jednobarevny stetec refreshBrush (); } 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.Color = panel.BackColor; refreshPen (); } } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/master/Draw/DrawForm.cs|DrawForm.cs]] ===== Reakce na změnu tužky ===== Parametry tužky a štetce budeme zobrazovat v dialogových oknech. Šířka tužky se navíc zobrazuje v horním //toolPanelu//. Pokud změníme parametry tužky nebo štetce, chceme parametry také znovu zobrazit. Vytvoříme //událost// informující různé části programu o změně tužky //Delegát// připomíná deklaraci funkce a uvedeme v něm parametr typu //Pen//. public delegate void PenHandler (Pen p); //Událost// pojmenujeme **penChanged** a bude obsahovat posloubnost funkcí (s halvičkami dle předchozí deklarace), které se mají zavolat public event PenHandler penChanged; Funkce **refreshPen** jednotlivé funkce zavolá public void refreshPen () { if (penChanged != null) penChanged (pen); } V konstruktoru pak do seznamu funkcí přidáme metodu **updatePenWidth** penChanged += updatePenWidth; Až //refreshPen// zavolá všechny funkce z posloupnosti, //updatePenWidth// zobrazí šířku tužky v horní částsti okna private void updatePenWidth (Pen p) { penWidthNumeric.Value = (int) p.Width; } Ve funkci **penMenuItem_Click** přidáme metodu dialogu **setPen** do seznamu funkcí, které se mají zavolat private void penMenuItem_Click (object sender, EventArgs e) { PenDialog dlg = new PenDialog (); dlg.setPen (pen); penChanged += dlg.setPen; // dialog bude informovan o zmenach dlg.form = this; // dialog bude pomoci form.refreshPen informovat o zmenach dlg.Show (); } A dialogovému oknu předáme odkaz na hlavní okno. \\ Pokocí **form.refreshPen ()** dialog oznámí hlavnímu oknu, že změnil tužku V //PenDialogu// v "design režimu" vybereme //propertyGrid//, v //Poperties// přejdeme na událostmi klikneme na **PropertyValueChanged** a vznikne funkce //propertyGrid_PropertyValueChanged// Pokud tedy v dialogovém boxu změníme vlastnosti tužky, zavoláme //refreshPen// v hlavním okně. A naopak, pokud někdo zavolá //refreshPen//, je zavolána metoda **setPen**, ktrá v tabulce zobrazí nový objekt. Zdrojový text dialogového okna public partial class PenDialog : Form { public PenDialog () { InitializeComponent (); } public void setPen (Pen p) { propertyGrid.SelectedObject = p; } public DrawForm form; private void propertyGrid_PropertyValueChanged (object s, PropertyValueChangedEventArgs e) { if (form != null) form.refreshPen (); } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/master/Draw/PenDialog.cs|PenDialog.cs]] ===== Reakce na změnu štětce ===== Obdobobně pro štětec v //DrawForm.cs// deklarujeme typ pro jednotlivé funkce a proměnnou obsahující seznam funkcí, které chceme zavolat při změně štětce public delegate void BrushHandler (BrushManipulator b); public event BrushHandler brushChanged; ( Přesněji: posloupnost neobsahuje obyčejné funkce, ale dvojice objekt a jeho metoda. ) Metoda, která zavolá funkce z uložené posloupnosti public void refreshBrush () { if (brushChanged != null) brushChanged (manipulator); } Vrátíme se do "designu" hlavního okna **DrawForm** \\ Do "Edit" menu přidáme položku "&Brush Properties", pojmenujeme ji **brushMenuItem** \\ Dvakrát kliknenme na novou položku menu (třídu BrushDialog ještě nemáme) private void brushMenuItem_Click (object sender, EventArgs e) { BrushDialog dlg = new BrushDialog (); dlg.setBrushManipulator (manipulator); brushChanged += dlg.setBrushManipulator; dlg.form = this; dlg.Show (); } ===== BrushDialog ===== Podobně jako v [[draw4#Dialogové okno s parametry pro kreslení čar|minulé kapitole]] V **Solution Exploreru** pravou myší klikneme na //projekt Draw// \\ Z kontextového menu vybereme **Add**, **Form (Windows Forms)** \\ Soubor pojmenujeme **BrushDialog.cs** * Do vzniklého okna přidáme z **Toolbox** ze skupiny **All Windows Forms** prvek **PropertyGrid** * přejmenujeme na **propertyGrid** * nastavíme **Dock** na **Fill** * mezi událostmi klikneme na **PropertyValueChanged** a vznikne funkce //propertyGrid_PropertyValueChanged// //BrushDialog// v //propertyGridu// zobrazuje parametry //BrushManipulátoru// public partial class BrushDialog : Form { public BrushDialog () { InitializeComponent (); } public void setBrushManipulator (BrushManipulator b) { propertyGrid.SelectedObject = b; } public DrawForm form; private void propertyGrid_PropertyValueChanged (object s, PropertyValueChangedEventArgs e) { if (form != null) form.refreshBrush (); } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/master/Draw/BrushDialog.cs|BrushDialog.cs]] {{draw_brush_prop.png}}