====== Jednoduchý kreslící program - ukládání do souboru ======
https://gitlab.fjfi.cvut.cz/culikzde/pw
* do menu File přidáme položku **&Open**, nastavíme zkratku **Ctrl+0**, pojmenujeme **openMenuItem**, přidáme reakci na Click
* dále přidáme položku **&Save**, nastavíme zkratku **Ctrl+S**, pojmenujeme **saveMenuItem**, přídáme reakci na Click
Menu je popsáno v [[draw3#Menu|minulé kapitole]]
* přidáme **OpenFileDialog**, pojmenujeme **openDialog**, (stačí vhodit kamkoliv do okna)
* přidáme **SaveFileDialog**, pojmenujeme **saveDialog**, (stačí vhodit kamkoliv do okna)
"Naklikáme" reakce na open a save a doplníme část programu
Pokud si uživatel vybere jméno souboru, zvolené jméno nalezneme v **openDialog.FileName**. \\
Třída **Bitmap** má konstruktor s jedním textovým parametrem - jménem souboru, který bude načten. \\
Pokud je nový obrázek menší než okno, použijeme pro zvětšení funkci **pictureBox_SizeChanged**, kterou popíšme "za chvilku".
private void openMenuItem_Click (object sender, EventArgs e)
{
if (openDialog.ShowDialog () == DialogResult.OK)
{
pictureBox.Image = new Bitmap (openDialog.FileName);
pictureBox_SizeChanged (null, null); // zvetsime bitmapu, pokud je obrazek mensi nez okno
}
}
Pro nahrávání do souboru použijeme metodu **pictureBox.Image.Save**. \\
První parametr je jméno souboru. \\
Druhý (nepovinný) parametr určuje formát souboru. \\
Na začátek programu musíme doplnit **using System.Drawing.Imaging;** obsahující **ImageFormat.Jpeg**
(//Using// direktivy někdy uvedu také v komentáři na příslušném místě programu jako upozornění, že direktivu musíme přidat na začátek souboru.)
private void saveMenuItem_Click (object sender, EventArgs e)
{
// using System.Drawing.Imaging;
if (saveDialog.ShowDialog () == DialogResult.OK)
pictureBox.Image.Save (saveDialog.FileName, ImageFormat.Jpeg);
}
===== Seznam barevných panelů a úprava konstruktoru =====
Odkazy na barevné panely budu ukládat do proměnné **colorTools** typu **List ** (obdoba typu //vector// v C++). \\
Ihned při deklaraci vytvtoříme prazdný seznam **new List ()** \\
Do seznamu přidáme první (modrý) panel ** colorTools.Add (colorPanel);** \\
Funkce //addColorPanel// nově vzniklé panely přidají na konec seznamu. \\
Barvu panelu s indexem 0 použijeme pro počáteční barvu tužky, barvu panelu s indexem 1 pro štětec.
private List colorTools = new List ();
public DrawForm ()
{
InitializeComponent ();
colorTools.Add (colorPanel); // modry panel
addColorPanel (Color.Yellow);
addColorPanel (Color.Red);
addColorPanel (Color.Green);
pen = new Pen (colorTools[0].BackColor); // modra barva podle prvniho panelu
brushColor = colorTools[1].BackColor; // zluta podle druheho panelu
brush = new SolidBrush (brushColor);
comboBox.SelectedIndex = (int) Shape.line;
pictureBox_SizeChanged (null, null); // vytvorime praznou bitmapu
}
Funkce //addColorPanel// již nepotřebuje proměnnou [[draw3#Více barevných panelů|panelCnt]], ale použije současnou délku seznamu.
void addColorPanel (Color c)
{
Panel p = new Panel (); // vytvorime novy panel
p.BackColor = c;
// novy panel umistime vpravo od soucasnych panelu
int cnt = colorTools.Count;
/* --> */ p.Left = colorPanel.Left + cnt * (colorPanel.Width + colorPanel.Left);
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
/* --> */ colorTools.Add (p);
}
===== Reakce na změnu velikosti okna =====
V "design" režimu vybereme **pictureBox** a přidáme reakci událost **SizeChanged**.
* Uložíme kopii původního obrázku do proměnné **old** (pokud již obrázek existuje)
* Zjistíme šířku a výšku okna s obrázkem
* Pokud byl původní obrázek širší nebo vyšší než současné okno, proměnné **w** a **h** zvětšíme
* Vytvoříme novou bitmapu, připojíme na ni //Graphics//, připravíme si bílý štětec a bitmapu vyplníme bílou barvou
* Do bitmapy nakopírujeme původni obrázek
* Bitmapu umístíme do okénka, bitmapa může být větší než okno, uvidíme jen část obrázku, ale okno můžeme zvětšit
* Na konci funkce zanikne proměnná **old** a s ní zanikne i bitmapa s původním obrázkem
private void pictureBox_SizeChanged (object sender, EventArgs e)
{
Bitmap old = null;
if (pictureBox.Image != null)
old = new Bitmap (pictureBox.Image); // kopie obrazku (pokud existuje)
int w = pictureBox.Width;
int h = pictureBox.Height;
if (old != null)
{
// pripadne zvetsime sirku a vysku, at neprijdeme o cast puvodniho obrazku
if (old.Width > w) w = old.Width;
if (old.Height > h) h = old.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); // vyplnime bilou barvou
if (old != null)
g.DrawImage (old, 0, 0); // obtiskneme puvodni obrazek
pictureBox.Image = b;
}
Funkci //pictureBox_SizeChanged// použijeme i v konstruktoru a při načtení nového obrázku ze souboru. \\
(Funkce nevyužívá své parametry, tak dosadíme dvakrát null.)
[[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/dde3f2ec/Draw/DrawForm.cs|gitlab]]
===== Štětec s barevným přechodem =====
Místo **SolidBrush** použijeme **LinearGradientBrush** (a doplníme using System.Drawing.Drawing2D;)
brush = new LinearGradientBrush (new PointF (0, 0), new PointF (100, 100), brushColor, secondBrushColor);
using System.Drawing.Drawing2D;
...
public DrawForm ()
{
InitializeComponent ();
colorTools.Add (colorPanel); // modry panel
addColorPanel (Color.Yellow);
addColorPanel (Color.Red);
addColorPanel (Color.Green);
pen = new Pen (colorTools[0].BackColor); // modra barva podle prvniho panelu
brushColor = colorTools[1].BackColor; // zluta podle druheho panelu
Color secondBrushColor = colorTools[2].BackColor;
brush = new LinearGradientBrush (new PointF (0, 0), new PointF (100, 100), brushColor, secondBrushColor);
...
{{draw_gradient.png}}
[[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/8b11a05d/Draw/DrawForm.cs|gitlab]]
===== Dialogové okno s parametry pro kreslení čar =====
V **Solution Exploreru** pravou myší klikneme na //projekt Draw// \\
Z kontextového menu vybereme **Add**, **Form (Windows Forms)** \\
Soubor pojmenujeme **PenDialog.cs**
{{draw_form.png}}
* 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**
{{draw_pen_dlg.png}}
Vrátíme se do "designu" hlavního okna **DrawForm** \\
Do "Edit" menu přidáme položku "&Pen Properties", pojmenujeme ji **penMenuItem** \\
( Pokud chceme přidat do menu oddělovací čáru, přidáme položku se textem obsahujícím jeden znak minus **"-"** )
{{draw_pen_menu.png}}
Dvakrát kliknenme na novou položku menu
Vytvoříme nový dialog, předáme mu odkaz na právě používanou tužku, dialogové okno zobrazíme
private void penMenuItem_Click (object sender, EventArgs e)
{
PenDialog dlg = new PenDialog ();
dlg.setPen (pen);
dlg.Show ();
}
Do souboru //PenDialog.cs// ještě musíme doplnit funkci **setPen**, tu napíšeme včetně hlavičky ("nenaklikáme")
public void setPen (Pen p)
{
propertyGrid.SelectedObject = p;
}
Odkaz na právě používanou tužku uložíme do ** propertyGrid.SelectedObject** a o zbytek práce se postará třída **PropertyGrid**
{{draw_pen_prop.png}}
[[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/1a7b51c0/Draw/DrawForm.cs|DrawForm]]
[[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/blob/1a7b51c0/Draw/PenDialog.cs|PenDialog]]