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; }
[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; } } }
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 (); } } }
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 (); } }
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 (); }
Podobně jako v minulé kapitole
V Solution Exploreru pravou myší klikneme na projekt Draw
Z kontextového menu vybereme Add, Form (Windows Forms)
Soubor pojmenujeme BrushDialog.cs
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 (); } }