[[pw:draw4]]
 

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 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 <Panel> (obdoba typu vector v C++).
Ihned při deklaraci vytvtoříme prazdný seznam new List <Panel> ()
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 <Panel> colorTools = new List <Panel> ();
 
        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 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.)

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);
 
            ...

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

  • 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

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 ”-“ )

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

DrawForm PenDialog

 
pw/draw4.txt · Last modified: 2020/11/03 15:35 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki