[[pw:draw2]]
 

Jednoduchý kreslící program - obdélník a elipsa

Upravíme panel s nástroji

V našem oknu dosud máme toolPanel (typu Panel) a pictureBox (typu PictureBox).

Přidáme z toolboxu Panel

Nastavíme BackColor např. na modrou barvu, přejmenujeme na colorPanel (nastavíme vlastnost (name) na colorPanel).
Pannelů pro výběr barvy potřebujeme více, ale další kopie vytvoříme až programem.
Z vizuálního návrhu použijeme jako vzorpvou velikost prvního colorPanelu a vzdálenost od okraje toolPanelu.

Přidáme ComboBox

  • přejmenujeme na comboBox (jména nejsou příliš vynalézavá, alespoň odstaním 1 na konci jména)
  • nastavíme DropDownStyle na DropDownList, aby uživatel nemohl kolonku editovat a mohl jen vybírat z připravebých hodnot
  • nastavíme Anchor na Top a Right, při změné velikosti okna si comboBox bude udržovat původní vzdálenost od pravého okraje okolního panelu

  • nastavíme Items na line, rectangle a ellipse. Jednotlivé hodnoty zadáme na samostané řádky ( bez dalších oddělovačů, za poslední hodnotou NENÍ žádná prázdná řádka, jinak by vznikla jedna položka bez jména)

Nastavit jako počáteční hodnotu na line musíme až jedním příkazem v konstruktoru.

Zavedeme si výčtový typ Shape.
A do comboBox.SelectedIndex uložíme konstantu pro čáru přetypovanou na int (nulu).
Hodnoty výčtivého typu se zapisují ve tvaru jméno typu, tečka a jméno položky, např. Shape.ellipse.
Přetypování se zapisuje jako v jazyce C, např. (int) n, ale toto přetypování kontroluje mnohem více situací než v jazyce C.

( Nebo si nadefinujeme tři celočíselné konstanty line, rectangle a ellipse. )

   public partial class DrawForm : Form
    {
        private enum Shape { line, rectangle, ellipse };
 
        // const int line = 0;
        // const int rectangle = 1;
        // const int ellipse = 2;
 
        public DrawForm ()
        {
            InitializeComponent ();
            comboBox.SelectedIndex = (int) Shape.line;

Proměnné pro používanou barvu

Deklarujeme proměnnou pen typu Pen a v této “pracovní tužce” budeme uchovávat barvu pro kreslení čar a okrajů.

Barvu pro vyplňování obrazců uložíme do proměnné brushColor typu Color.

Pro vyplňování budeme používat “štětec” uložený v proměnné brush typu Brush.

Proměnné pen a brush jsou objektového typu.
V C# jsou to odkazy (v C ukazatele).
( V deklaraci typu nepoužíváme * jako v C. )
( Také nepoužíváme - > , píšeme jen tečku. )

Ze základní třídy Brush je odvozeno několik tříd. My budeme používat SolidBrush pro jednobarevnou výplň.
Později použijeme výplně s barevnými přechody. K barvě štětce se již tak snadno nedostaneme, proto ji skladujeme v proměnné brushColor.

Typ Color je deklarován jako struct (nikoliv class jako předešlé objektové typy.)
V C# struct znamená, že hodnoty (v našem případě typu Color) nejsou dostupné přes ukazatel (v C++ by to byl typ s “hvězdičkou” Color * ),
ale jsou uloženy přímo ve vícebytové proměnné (dle velikosti struktury) (v C++ by to byl typ “bez hvězdičky” Color )

    public partial class DrawForm : Form
    {
        private Pen pen;
 
        private Brush brush;
        private Color brushColor;
 
        private enum Shape { line, rectangle, ellipse };
 
        public DrawForm ()
        {
            InitializeComponent ();
 
            pen = new Pen (Color.Red);
 
            brushColor = Color.Yellow;
            brush = new SolidBrush (brushColor);
 
            comboBox.SelectedIndex = (int)Shape.line;

Proměnné pen a brush jsou na úrovni třídy a tak jsou automaticky inicializovány na null.
My do nich uložíme červenou tužku a žlutý štětec.

private, protected, public platí jen pro následující deklaraci (až do sředníku)
( Pokud neuvedene ani jedno klíčové slovo, pro třídy a struktury se použije private. )

Globální proměnné v C# nejsou povoleny.
Pro nás mají proměnné na úrovni třídy dobrou vlastnost, že pokud vytvoříme několik instancí okna, tak každé může používat svoji barvu.

Nakreslíme obdélník a elipsu

Vnitřek elipsy vyplňíme funkcí FillEllipse, okraj nakreslíme funkcí DrawEllipse

        g.FillEllipse (brush, X0, Y0, e.X - X0, e.Y - Y0);
        g.DrawEllipse (pen, X0, Y0, e.X - X0, e.Y - Y0);

Proměnná g je Graphics pripojený na náš pictureBox.Image

Prarametry jsou použitá tužka nebo štětec,
souřadnice levého horního roku opsanému obdélníku dané elipsy,
šířka a výška obdélníku.

Pro záporné šířka a/nebo výšky se nakreslí elipsy, které uživatel nejspíše měl na mysli.
( Stisknout myš, táhnout nahoru a/nebo vlevo a potom pustit myš. )
( Souřadná soustava obrázku má počátek v levém horním rohu a osa y míří dolů. )

V případě obdélníku funkce FillRectangle a DrawRectangle pro záporné výšky a šířky nic nenakreslí.
Musíme si počáteční X0,Y0 případně prohodit s koncovým e.X,e.Y
( Nesmíme změnit původní X0 a Y0, budeme je potřebovat při kreslení dalšího náhledu na vznikající obdélník. )

Vše se odehrává v pictureBox_MouseMove.
Pokud je myš stisknuta obnovíme obraz na stav při stisku a podíváme se do comboBoxu jakým nástrojem máme kreslit.

        private int X0, Y0;
        private bool press = false;
        private Image save;
 
        private void pictureBox_MouseDown (object sender, MouseEventArgs e)
        {
            X0 = e.X;
            Y0 = e.Y;
            press = true;
            save = new Bitmap (pictureBox.Image);
        }
 
        private void pictureBox_MouseMove (object sender, MouseEventArgs e)
        {
            if (press)
            {
                Graphics g = Graphics.FromImage (pictureBox.Image);
                g.DrawImage (save, 0, 0);
 
                Shape inx = (Shape) comboBox.SelectedIndex;
                if (inx == Shape.line)
                {
                    g.DrawLine (pen, X0, Y0, e.X, e.Y);
                }
                else if (inx == Shape.rectangle)
                {
                    int X1 = X0;
                    int Y1 = Y0;
                    int X2 = e.X;
                    int Y2 = e.Y;
                    if (X2 < X1) { int t = X1; X1 = X2; X2 = t; }
                    if (Y2 < Y1) { int t = Y1; Y1 = Y2; Y2 = t; }
                    g.FillRectangle (brush, X1, Y1, X2 - X1, Y2 - Y1);
                    g.DrawRectangle (pen, X1, Y1, X2 - X1, Y2 - Y1);
                }
                else if (inx == Shape.ellipse)
                {
                    g.FillEllipse (brush, X0, Y0, e.X - X0, e.Y - Y0);
                    g.DrawEllipse (pen, X0, Y0, e.X - X0, e.Y - Y0);
                }
 
                pictureBox.Invalidate ();
            }
        }
 
        private void pictureBox_MouseUp (object sender, MouseEventArgs e)
        {
            press = false;
        }

stav z tohoto okamžiku na gitlab

 
pw/draw2.txt · Last modified: 2020/10/20 11:52 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