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