10. Editor obrázků C++ Builderu
  1. Editor obrázků je vizuální editor. Můžeme jej použít k vytváření a editaci obrázků, které chceme použít v naší aplikaci. K otevření editoru obrázků zvolíme Tools | Image Editor. Editor obrázků zobrazí nové okno, kde můžeme vytvářet, otvírat a ukládat různé typy souborů obrázků (ikon, kurzorů a bitových map). Okno má svou vlastní nabídku, paletu barev, paletu nástrojů a další palety.

  2. Editor obrázků můžeme použít k vytváření obrázků pro naši aplikaci. Pro vytvoření nového obrázku zvolíme File | New, k otevření existujícího obrázku zvolíme File | Open a pro uložení obrázku zvolíme File | Save nebo File | Save As.
    Editor obrázků umožňuje provádět tyto činnosti: Volby v nabídce mají obvyklý význam a používají se běžným způsobem. Paleta nástrojů se také používá běžným způsobem.
    Pokuste se pomocí Editoru obrázků nakreslit nějaký obrázek a použijte jej v nějaké aplikaci.

  3. Jsou tři možnosti použití grafiky v aplikaci C++ Builderu: můžeme vložit předem vytvořený obrázek během návrhu, vytvořit jej použitím grafického ovladače při návrhu nebo jej dynamicky kreslit při běhu aplikace. V této kapitole se budeme dále zabývat kreslením za běhu aplikace a to buď na formulář nebo na nějakou komponentu. Grafické komponenty VCL zaobalují GDI Windows (Graphics Device Interface) a značně usnadňují přidávání grafických možností do našich programů.

  4. Když kreslíme v aplikaci C++ Builderu, můžeme kreslit na plátno (canvas) objektu; je to vhodnější než kreslit přímo na objekt. Plátno je vlastnost objektu a je to samotný objekt se svými vlastními vlastnostmi. Hlavní výhodou objektu plátna je to, že efektivně využívá zdroje systému a naše programy mohou používat stejné metody a to bez ohledu na to, zda manipulujeme s bitovými mapami nebo metasoubory. Plátna jsou dostupná pouze za běhu aplikace a můžeme tedy s nimi pracovat pouze prostřednictvím kódu. Jelikož TCanvas je obal okolo kontextu zařízení Windows, lze také používat všechny funkce GDI Windows pro plátno. Vlastnost Handle plátna je kontext zařízení.
    Objekt plátna má pět důležitých vlastností: pero pro kreslení čar (Pen), štětec pro vyplňování tvarů (Brush), písmo pro zápis textů (Font), současnou pozici pera (PenPos) a pole bodů reprezentujících obraz (Pixels). Několik metod objektu plátna je popsáno v následující tabulce.
     
    Metoda Popis
    Arc Kreslí eliptický oblouk.
    Chord Kreslí eliptickou úseč.
    CopyRect Kopíruje část obrázku z jednoho plátna na jiné.
    Draw Zobrazuje specifikovanou grafiku na plátně.
    Ellipse Kreslí elipsu.
    FillRect Vyplňuje specifikovaný obdélník na plátně současným štětcem.
    FloodFill Zaplňuje oblast plátna současným štětcem.
    FrameRect Kreslí rámeček plátna.
    LineTo Kreslí úsečku z PenPos do specifikovaného bodu a PenPos nastaví na tento bod. 
    MoveTo Nastavuje PenPos na zadané souřadnice.
    Pie Kreslí eliptickou výseč.
    Polygon Propojuje předané body úsečkami a uzavírá nakreslený tvar.
    PolyLine Propojuje předané body úsečkami.
    Rectangle Kreslí obdélník současným perem a vyplňuje jej současným štětcem.
    RoundRect Kreslí obdélník se zaoblenými rohy.
    StretchDraw Kreslí grafiku na plátně tak, aby obrázek zaplnil specifikovaný obdélník.
    TextHeight, 
    TextWidth
    Vrací výšku a šířku řetězce zapsaného současným písmem. Výška obsahuje i mezeru mezi řádky.
    TextOut Zapisuje řetězec na plátno.
    TextRect Zapisuje řetězec do obdélníkové oblasti. Části textu mimo oblast se nezobrazují.

    Když pracujeme s grafikou, je nutno si uvědomit rozdíl mezi kreslením a malováním. Rozdílným významem těchto pojmů jsme se již zabývali.
    V jistých okamžicích Windows určuje, že objekty zobrazené na obrazovce mají obnovit svůj vzhled. Provádí to generováním zprávy wm_Paint, kterou VCL převádí na událost OnPaint. Když použijeme metodu Refresh, C++ Builder volá obsluhu události OnPaint objektu. Jak se grafika zobrazuje v naší aplikaci, závisí na způsobu jejího kreslení. Pokud kreslíme přímo na plátno ovladače, pak objekt obrázku je zobrazován bezprostředně. Můžeme ale kreslit mimo obrazovku na plátno TBitmap a obrázek se zobrazí až po překopírování z plátna TBitmap na plátno ovladače.
    C++ Builder používá následující grafické objekty:
     

    Objekt Popis
    Picture Používá se k držení obrázku. K přidání dalších grafických formátů, používáme metodu Register. Takto lze použít libovolné soubory obrázků k zobrazení na ovladači.
    Bitmap Grafický objekt používaný k vytváření, manipulaci (změna měřítka, rotace apod.) a ukládání obrázků. Vytváření kopie je rychlé, neboť je kopírováno madlo a ne obrázek.
    Clipboard Reprezentuje kontejner pro libovolný text nebo grafiku, kterou můžeme vystřihovat, kopírovat a vkládat z nebo do aplikace. 
    Icon Reprezentuje hodnotu zavedenou ze souboru ikony (soubor ICO).
    Metafile Obsahuje grafiku metasouboru.
  5. Vlastnost Pen plátna řídí způsob zobrazování čar, včetně kreslení čar obrysů tvarů. Kreslení rovné čáry změní skupinu bodů, které jsou přímo mezi dvěma body. Samotné pero má čtyři vlastnosti, které můžeme měnit: Color, Width, Style a Mode. Hodnoty těchto vlastností určují jak pero změní body na čáře. Implicitně každé pero začíná s černou barvou, se šířkou 1 bod, plnou čarou a režimem nazvaným pmCopy, který přepisuje body na plátně.

  6. Barvu pera můžeme nastavit při běhu aplikace změnou vlastnosti Color. Barva pera určuje barvu kreslené čáry. Width je celé číslo určující šířku čáry v bodech. Pokud kreslíme čáru silnější než jeden bod, pak Windows vždy kreslí plné čáry (neuvažuje se hodnota vlastnosti Style). Style umožňuje používat plnou čáru, tečkovanou čáru, čárkovanou čáru apod. Mode slouží k určení způsobu kombinace barvy pera s původní barvou v poli bodů.
    Aktuální kreslící pozice (pozice, kde jsme skončili s kreslením předchozí čáry) se nazývá pozice pera. Plátno ukládá svoji pozici pera do vlastnosti nazvané PenPos. Pozici pera ovlivňuje pouze kreslení čar; pro tvary a texty zadáváme všechny požadované souřadnice. K nastavení pozice pera voláme metodu MoveTo plátna. Např. k přesunu pozice pera do horního levého rohu plátna použijeme následující kód:
    Canvas->MoveTo(0, 0);
    Kreslení čáry metodou LineTo také přesouvá pozici pera do koncového bodu čáry.
    Vlastnost Brush plátna řídí způsob vyplňování oblastí, včetně vyplňování tvarů. Vyplňování oblasti štětcem způsobí změnu většího počtu určených bodů. Štětec má tři vlastnosti, které můžeme měnit: Color, Style a Bitmap. Hodnoty těchto vlastností určují způsob vyplňování tvarů nebo jiných oblastí plátna. Implicitně každý štětec začíná bílou barvou, plným stylem a bez vzoru bitové mapy. Barvu štětce můžeme nastavit pomocí vlastnosti Color. Style určuje vzor použitý k vyplnění tvaru. Předdefinované hodnoty této vlastnosti určují různé typy šrafování. Bitmap slouží ke specifikaci obrázku pro štětec k použití jako vzor pro vyplňování tvarů a jiných oblastí.
    Každé plátno má indexovanou vlastnost nazvanou Pixels, která reprezentuje jednotlivé barevné body obrázku na plátně. K vlastnosti Pixels přistupujeme přímo pouze když potřebujeme zjistit nebo nastavit barvu konkrétního bodu. Pixels představuje kreslící plochu plátna a pero nebo štětec pracují se skupinou bodů. Používání této vlastnosti zpomaluje grafické operace.
  7. Na plátno můžeme kreslit dva typy čar: přímé čáry a lomené čáry. Přímá čára je čára spojující dva body. Lomená čára je řetězec přímých čar, které na sebe navazují. Všechny čary kreslíme pomocí pera. Ke kreslení přímých čar na plátně používáme metodu LineTo plátna. LineTo kreslí čáru z aktuální pozice pera do bodu určujícího koncový bod čáry. Plátno kreslí čaru pomocí svého pera. Např. následující metoda nakreslí úhlopříčky formuláře při malování formuláře (uvedené příkazy tvoří obsluhu OnPaint formuláře):

  8. Canvas->MoveTo(0, 0);
    Canvas->LineTo(ClientWidth, ClientHeight);
    Canvas->MoveTo(0, ClientHeight);
    Canvas->LineTo(ClientWidth, 0);
    Událost OnPaint vznikne, když Windows zjistí, že je potřeba formulář překreslit. Mimo samostatných čar, plátno může také kreslit lomené čáry, což je skupina několika propojených čárových segmentů. Pro kreslení lomené čáry na plátno, voláme metodu Polyline plátna. Parametr předávaný metodě Polyline je pole bodů. Tato metoda provede MoveTo do prvního bodu a LineTo do každého následujícího bodu. Následující příkazy např. kreslí na formuláři kosočtverec:
    POINT body[5];
    body[0] = Point(0, 0);
    body[1] = Point(50, 0);
    body[2] = Point(75, 50);
    body[3] = Point(25, 50);
    body[4] = Point(0, 0);
    Canvas->Polyline(body, 4);
    Druhý parametr metody Polyline je index posledního prvku a ne počet bodů.
  9. Plátna mají metody pro kreslení různých typů tvarů. Plátno kreslí obrys tvaru svým perem a vnitřek tvaru vyplňuje svým štětcem. Pro kreslení obdélníku nebo elipsy na plátnu, voláme metodu Rectangle nebo Ellipse plátna a předáme souřadnice ohraničujícího obdélníku. Metoda Rectangle kreslí ohraničující obdélník, Ellipse kreslí elipsu vloženou do obdélníku. Následující příkazy např. kreslí obdélník do horní levé čtvrtiny formuláře a pak do stejné oblasti nakreslí elipsu:

  10. Canvas->Rectangle(0, 0, ClientWidth / 2, ClientHeight / 2);
    Canvas->Ellipse(0, 0, ClientWidth / 2, ClientHeight / 2);
    Pro kreslení obdélníků se zaoblenými rohy na plátno, voláme metodu RoundRect plátna. První čtyři parametry předané RoundRect určují ohraničující obdélník (stejně jako u Rectangle) a další dva parametry určují zaoblení rohů. Následující příkaz např. kreslí obdélník se zaoblenými rohy do horní levé čtvrtiny formuláře a zaoblené rohy jsou tvořeny čtvrtinou kružnice o poloměru 10 bodů:
    Canvas->RoundRect(0,0,ClientWidth / 2,ClientHeight / 2, 10, 10);
    Pro kreslení mnohoúhelníku na plátno, voláme metodu Polygon plátna. Mnohoúhelník přebírá pole bodů jako svůj jediný parametr a tyto body propojuje čarou nakreslenou perem (spojí také poslední bod s prvním k uzavření mnohoúhelníku). Po nakreslení čar je použit štětec k vyplnění mnohoúhelníku. Následuje příklad použití (pravoúhlý trojúhelník):
    POINT body[3];
    body[0] = Point(0, 0);
    body[1] = Point(0, ClientHeight);
    body[2] = Point(ClientWidth,ClientHeight);
    Canvas->Polygon(body,2);
    Mimo kreslení čar a tvarů, které jsou zde popsány, plátno také poskytuje některé specializované grafické možnosti, jako eliptický oblouk, eliptická výseč apod. Můžeme také vyplňovat oblasti a kopírovat obrázky na jiné plátno. Informace o těchto možnostech najdeme v nápovědě.
    Vyzkoušejte použití výše uvedených příkazů.
  11. Dále se seznámíme s používáním událostí myši pro kreslení. Začneme s vývojem nové aplikace. Vytvoříme obsluhu události OnMouseDown formuláře k nastavení aktuální kreslící pozice na souřadnice, kde uživatel stiskl tlačítko myši:

  12. Canvas->MoveTo(X, Y);
    Stisknutí tlačítka myši nyní nastaví pozici pera, tj. nastaví počáteční bod čáry. Ke kreslení čáry je ještě zapotřebí bod, kde uživatel tlačítko myši uvolní. To určíme v obsluze události OnMouseUp. Tato událost je obvykle zaslána objektu, nad kterým bylo tlačítko myši stisknuto. V naši aplikaci vytvoříme obsluhu události OnMouseUp formuláře a předané souřadnice použijeme jako koncový bod čáry. Tato obsluha události bude vypadat takto:
    Canvas->LineTo(X, Y);
    Aplikaci můžeme vyzkoušet a nakreslit několik čar. Událost OnMouseMove se při pohybu myši vyskytuje periodicky. Událost je zasílána objektu, nad kterým bylo tlačítko myši stisknuto. V našem příkladu použijeme událost přemístění myši pro kreslení čáry podle pohybu myši. To dosáhneme použitím následující obsluhy události OnMouseMove formuláře:
    Canvas->LineTo(X, Y);
    Nyní jestliže spustíme aplikaci, pak pohybem myši po formuláři kreslíme čáru. Musíme ještě zajistit, aby kreslení probíhalo pouze při stisknutém tlačítku. V našem příkladu, je zapotřebí, aby formulář udržoval informaci o tom, zda tlačítko myši je stisknuto. K tomuto účelu do deklarace typu formuláře přidáme do veřejné části položku Drawing typu bool a nastavíme její hodnotu při stisku tlačítka myši. Později budeme potřebovat další dvě položky, obě typu POINT. Jedná se o položky Origin a MovePt.
    bool Drawing;
    POINT Origin, MovePt;
    V položce Drawing budeme udržovat informaci o tom, zda kreslit. Při stisku tlačítka ji nastavíme na true a při jeho uvolnění na false. V tomto smyslu změníme již vytvořené obsluhy události. Pro OnMouseDown použijeme příkazy:
    Drawing = true;
    Canvas->MoveTo(X, Y);
    a pro OnMouseUp příkazy:
    Canvas->LineTo(X, Y);
    Drawing = false;
    Dále musíme modifikovat obsluhu události OnMouseMove tak, aby kreslení probíhalo pouze tehdy, když Drawing má hodnotu true:
    if (Drawing) Canvas->LineTo(X, Y);
    Nyní kreslení probíhá pouze mezi stiskem tlačítka a jeho uvolněním. Pokaždé, při přesunu myši, obsluha události OnMouseMove volá LineTo, které mění pozici pera. Při uvolnění tlačítka myši již tedy neznáme počáteční bod čáry. Abychom po skončení kreslení mohli propojit počáteční bod křivky s koncovým a křivku tak uzavřít, použijeme položku Origin k uložení počátečního bodu křivky. Změníme tedy obsluhy událostí takto: pro OnMouseDown použijeme:
    Drawing = true;
    Canvas->MoveTo(X, Y);
    Origin = Point(X, Y);
    a pro OnMouseUp:
    Canvas->MoveTo(Origin.X, Origin.Y);
    Canvas->LineTo(X, Y);
    Drawing = false;
    Obsluha události OnMouseMove je nyní napsána tak, že jsou kresleny čáry z poslední pozice myši do aktuální pozice. Můžeme to změnit tak, aby kreslené čáry začínaly v bodě stisku tlačítka myši:
    if (Drawing){
      Canvas->MoveTo(Origin.X, Origin.Y);
      Canvas->LineTo(X, Y);
    }
    Vyzkoušejte. Pro rozumnou práci této aplikace bychom potřebovali, aby vždy před nakreslením další čáry byla předchozí čára smazána. Využijeme k tomu položku MovePt, kde bude uložen koncový bod předchozí nakreslené čáry. Naše obsluhy událostí změníme takto. Pro OnMouseDown použijeme:
    Drawing = true;
    Canvas->MoveTo(X, Y);
    Origin = Point(X, Y);
    MovePt = Point(X, Y);
    a pro OnMouseMove:
    if (Drawing) {
      Canvas->Pen->Mode = pmNotXor;
      Canvas->MoveTo(Origin.X, Origin.Y);
      Canvas->LineTo(MovePt.X, MovePt.Y);
      Canvas->MoveTo(Origin.X, Origin.Y);
      Canvas->LineTo(X, Y);
    }
    MovePt = Point(X,Y);
    Canvas->Pen->Mode = pmCopy;
    Nyní po spuštění aplikace se námi kreslená čára průběžně zobrazuje a zůstane zobrazená pouze ta, při které jsme uvolnili tlačítko myši. Je to dosaženo tím, že při zápisovém režimu pmNotXor druhé zobrazení stejné čáry tuto čáru smaže. Na závěr kreslení je opět nastaven implicitní zápisový režim pmCopy.
10. Editor obrázků C++ Builderu