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