11. Prßce s grafikou I
  1. Nynφ se budeme zab²vat aplikacφ grafickΘho editoru. Budeme zde pou₧φvat palety nßstroj∙ (bude zapot°ebφ mnoho obrßzk∙) a abychom je nemuseli vytvß°et sami op∞t si stßhneme ji₧ hotovou aplikaci. Nßsleduje popis tΘto aplikace. Na formulß° jsou vlo₧eny t°i komponenty Panel. Majφ nastaveny vlastnosti Align na alTop (tφm zabφrajφ celou Üφ°ku formulß°e), majφ zruÜen² titulek a obsahujφ tlaΦφtka.

  2. TlaΦφtka na hornφm panelu se jmenujφ: LineButton, RectangleButton, EllipseButton, RoundRectButton, PenButton a BrushButton. Majφ p°i°azeny vhodnΘ obrßzky. U prvnφho tlaΦφtka je nastavena jeho vlastnost Down na true a z prvnφch Φty° tlaΦφtek je vytvo°ena skupina (GroupIndex je nastaveno na 1). TlaΦφtka Pera a èt∞tce (poslednφ dv∞ tlaΦφtka) jsou jedno tlaΦφtkovΘ skupiny, kterΘ pracujφ jako p°epφnacφ. Majφ nastaveny vlastnosti AllowAllUp na true a vlastnost GroupIndex pro PenButton na 2 a pro BrushButton na 3.
    Budeme se sna₧it vytvo°enou paletu nßstroj∙ zapojit do prßce. Zapamatujeme si zvolen² nßstroj a p°i dalÜφ prßci jej budeme pou₧φvat. K zapamatovßnφ zvolenΘho nßstroje je nejvhodn∞jÜφ pou₧φt v²Φtov² typ. P°idßme tedy p°ed deklaraci typu formulß°e deklaraci v²ΦtovΘho typu TDrawingTool a slo₧ku DrawingTool tohoto typu vlo₧φme do ve°ejnΘ Φßsti deklarace typu formulß°e (jsou zde p°idßny i slo₧ky, o kter²ch jsme se zmφnili na zßv∞r p°edchozφ kapitoly a slo₧ka pro ulo₧enφ jmΘna souboru):
    enum TDrawingTool {dtLine, dtRectangle, dtEllipse, dtRoundRect};

    bool Drawing;
    TPoint Origin, MovePt;
    TDrawingTool DrawingTool;
    AnsiString CurrentFile;
    Zm∞nu nßstroje provßdφme v reakci na udßlost OnClick stisknutΘho tlaΦφtka. Vytvo°φme tedy nßsledujφcφ obsluhy udßlostφ:
    void __fastcall TForm1::LineButtonClick(TObject *Sender)
    {
      DrawingTool = dtLine;
    }
    void __fastcall TForm1::RectangleButtonClick(TObject *Sender)
    {
      DrawingTool = dtRectangle;
    }
    void __fastcall TForm1::EllipseButtonClick(TObject *Sender)
    {
      DrawingTool = dtEllipse;
    }
    void __fastcall TForm1::RoundRectButtonClick(TObject *Sender)
    {
      DrawingTool = dtRoundRect;
    }
    Nynφ ji₧ m∙₧eme °φci formulß°i, kter² typ nßstroje mß pou₧φt a je nutno jeÜt∞ formulß° nauΦit jak jej mß pou₧φt. Kreslφcφ nßstroj se pou₧φvß v obsluhßch udßlostφ OnMouseUp a OnMouseMove. Tyto obsluhy vyu₧φvajφ zvolen² nßstroj (jeden ze Φty° mo₧n²ch) k provedenφ kreslenφ.
    void __fastcall TForm1::FormMouseUp(TObject *Sender,
        TMouseButton Button, TShiftState Shift, int X, int Y)
    {
      switch (DrawingTool){
        case dtLine:
           Canvas->MoveTo(Origin.X, Origin.Y);
           Canvas->LineTo(X, Y);
           break;
        case dtRectangle:
           Canvas->Rectangle(Origin.X, Origin.Y, X, Y);
           break;
        case dtEllipse:
           Canvas->Ellipse(Origin.X, Origin.Y, X, Y);
           break;
        case dtRoundRect:
           Canvas->RoundRect(Origin.X, Origin.Y, X, Y,
           (Origin.X - X) /2, (Origin.Y - Y) / 2);
           break;
      }
      Drawing = false;
    }
    void __fastcall TForm1::FormMouseMove(TObject *Sender,
         TShiftState Shift, int X, int Y)
    {
      if (Drawing) {
        Canvas->Pen->Mode = pmNotXor;
        switch (DrawingTool) {
          case dtLine:
                    Canvas->MoveTo(Origin.X, Origin.Y);
                    Canvas->LineTo(MovePt.X, MovePt.Y);
                    Canvas->MoveTo(Origin.X, Origin.Y);
                    Canvas->LineTo(X, Y);
                    break;
          case dtRectangle:
              Canvas->Rectangle(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
              Canvas->Rectangle(Origin.X, Origin.Y, X, Y);
              break;
          case dtEllipse:
              Canvas->Ellipse(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
              Canvas->Ellipse(Origin.X, Origin.Y, X, Y);
              break;
          case dtRoundRect:
              Canvas->RoundRect(Origin.X, Origin.Y, MovePt.X, MovePt.Y,
               (Origin.X - MovePt.X) / 2, (Origin.Y - MovePt.Y) / 2);
              Canvas->RoundRect(Origin.X, Origin.Y, X, Y,
               (Origin.X - X) / 2, (Origin.Y - Y) / 2);
              break;
        }
        MovePt = Point(X,Y);
      }
      Canvas->Pen->Mode = pmCopy;
    }
    V t∞chto metodßch se n∞kolikrßt opakuje stejn² k≤d. Tento opakujφcφ se k≤d vlo₧φme do samostatnΘ metody, kterou v obou obsluhßch pou₧ijeme. Deklarace metody DrawShape je vlo₧ena do ve°ejnΘ Φßsti (na jejφ konec) deklarace typu formulß°e (mohli bychom ji vlo₧it i do soukromΘ Φßsti):
    void __fastcall DrawShape(TPoint TopLeft, TPoint BottomRight,
                              TPenMode AMode);
    Definice tΘto metody je zapsßna do programovΘ jednotky. Metoda mß tento tvar:
    void __fastcall TForm1::DrawShape(TPoint TopLeft, TPoint BottomRight,
                                      TPenMode AMode){
      Canvas->Pen->Mode = AMode;
      switch (DrawingTool){
        case dtLine :
          Canvas->MoveTo(TopLeft.x, TopLeft.y);
          Canvas->LineTo(BottomRight.x, BottomRight.y);
          break;
        case dtRectangle :
          Canvas->Rectangle(TopLeft.x, TopLeft.y,
                            BottomRight.x, BottomRight.y);
          break;
        case dtEllipse :
          Canvas->Ellipse(TopLeft.x, TopLeft.y,
                          BottomRight.x, BottomRight.y);
          break;
        case dtRoundRect :
          Canvas->RoundRect(TopLeft.x, TopLeft.y, BottomRight.x,
                            BottomRight.y, (TopLeft.x - BottomRight.x)/2,
                            (TopLeft.y - BottomRight.y)/2);
          break;
        }
    }
    Tato metoda je pou₧ita k dßle uvedenΘmu zjednoduÜenφ naÜich obsluh udßlostφ:
    void __fastcall TForm1::FormMouseUp(TObject *Sender,
                    TMouseButton Button, TShiftState Shift, int X, int Y)
    {
      if (Drawing){
        DrawShape(Origin, Point(X, Y), pmCopy);
        Drawing = false;
      }
    }
    void __fastcall TForm1::FormMouseMove(TObject *Sender,
                    TShiftState Shift, int X, int Y)
    {
      if (Drawing){
        DrawShape(Origin, MovePt, pmNotXor);
        MovePt = Point(X, Y);
        DrawShape(Origin, MovePt, pmNotXor);
      }
    }
    Tφm mßme volbu kreslφcφho nßstroje vy°eÜenou.

  3. Dßle se budeme zab²vat dalÜφmi paletami nßstroj∙ (jedna se t²kß pera a druhß Üt∞tce). Paleta nßstroj∙ nemusφ b²t stßle viditelnß. Pokud aplikace obsahuje mnoho palet nßstroj∙, pak zobrazujeme pouze tu, kterou prßv∞ pou₧φvßme. K vytvo°enφ skrytΘ palety nßstroj∙ nastavφme vlastnost panelu Visible na false. V naÜi aplikaci mßme dv∞ dalÜφ komponenty panelu (budou reprezentovat skrytΘ palety), jeden je nazvan² PenBar a druh² BrushBar (jsou zruÜeny hodnoty jejich vlastnostφ Caption). Vlastnosti komponent jsou nastaveny podle dalÜφho popisu (ovladaΦe jsou uvßd∞ny zleva doprava). U prvnφch osmi tlaΦφtek z BrushBar (vzory v²pln∞) je nastavena vlastnost GroupIndex na 1 a u prvnφch Üesti tlaΦφtek z PenBar (typy Φar) je nastavena GroupIndex takΘ na 1.

  4. TlaΦφtka na BrushBar  jsou nazvßna takto: SolidBrush, ClearBrush, VerticalBrush, HorizontalBrush, FDiagonalBrush, BDiagonalBrush, CrossBrush, DiagCrossBrush a BrushColor. U prvnφho tlaΦφtka je nastavena vlastnost Down na true. Obdobn∞ pro PenBar se tlaΦφtka jmenujφ: SolidPen, DashPen, DotPen, DashDotPen, DashDotDotPen, ClearPen a PenColor. Prvnφ tlaΦφtko je op∞t stisknutΘ. Na tΘto palet∞ je umφst∞n takΘ editaΦnφ ovladaΦ nazvan² PenSize a vlastnost Text je u n∞j nastavena na 1. K tomuto editaΦnφmu ovladaΦi je p°ipojena komponenta UpDown (je pojmenovanß PenWidth a jejφ vlastnost Associate je nastavena na PenSize).
    K ukrytφ nebo zobrazenφ palety nßstroj∙ m∞nφme jejφ vlastnost Visible na false nebo true. Obvykle to provßdφme v reakci na jistou udßlost nebo zm∞nu re₧imu aplikace. V naÜem p°φpad∞ skrytφ a zobrazovßnφ palety pera a Üt∞tce budeme ovlßdat tlaΦφtky PenButton a BrushButton, tedy obsluhami jejich stisku.
    void __fastcall TForm1::PenButtonClick(TObject *Sender)
    {
      PenBar->Visible = PenButton->Down;
    }
    void __fastcall TForm1::BrushButtonClick(TObject *Sender)
    {
      BrushBar->Visible = BrushButton->Down;
    }
    Jestli₧e nynφ spustφme naÜi aplikaci, m∙₧eme zobrazovat a ukr²vat paletu pera a paletu Üt∞tce (jsou umφst∞ny v hornφ Φßsti formulß°e pod paletou kreslφcφch nßstroj∙).
    Styl pera urΦuje typ zobrazovanΘ Φßry (plnß, Φßrkovanß, teΦkovanß atd.). Ke zm∞n∞ stylu pera, nastavφme vlastnost pera Style na hodnotu urΦujφcφ po₧adovan² styl. Je mo₧no pou₧φt n∞kterou z nßsledujφcφch konstant: psSolid, psDash, psDot, psDashDot, psDashDotDot nebo psClear. M∙₧eme tedy pro ka₧dΘ tlaΦφtko urΦujφcφ styl vytvo°it obsluhu udßlosti OnClick a p°i°adit v nφ odpovφdajφcφ konstantu vlastnosti Style. V naÜem programu budeme ale postupovat jin²m zp∙sobem. Pro vÜechna tato tlaΦφtka vytvo°φme sdφlenou obsluhu udßlosti (nazveme ji SetPenStyle) a stisknutΘ tlaΦφtko v nφ urΦφme pomocφ parametru Sender.
    void __fastcall TForm1::SetPenStyle(TObject *Sender)
    {
        if (Sender == SolidPen) Canvas->Pen->Style = psSolid;
        else if (Sender == DashPen) Canvas->Pen->Style = psDash;
        else if (Sender == DotPen) Canvas->Pen->Style = psDot;
        else if (Sender == DashDotPen) Canvas->Pen->Style = psDashDot;
        else if (Sender == DashDotDotPen) Canvas->Pen->Style = psDashDotDot;
        else if (Sender == ClearPen) Canvas->Pen->Style = psClear;
    }
    Barva pera urΦuje barvu kreslenΘ Φßry, vΦetn∞ obrys∙ kreslen²ch tvar∙. Pro zm∞nu barvy pera zm∞nφme vlastnost pera Color. Barvu zadßvßme volbou v dialogovΘm okn∞ barev Windows. Na formulß°i je komponenta ColorDialog, a je vytvo°ena nßsledujφcφ obsluha udßlosti OnClick pro tlaΦφtko PenColor:
    ColorDialog1->Color = Canvas->Pen->Color;
    if (ColorDialog1->Execute())
      Canvas->Pen->Color = ColorDialog1->Color;
    èφ°ka pera urΦuje tlouÜ¥ku Φßry v bodech. Ke zm∞n∞ Üφ°ky pera p°i°adφme Φφselnou hodnotu vlastnosti pera Width. Obsluha udßlosti OnChange editaΦnφho ovladaΦe PenSize je tvo°ena p°φkazem:
    Canvas->Pen->Width = PenWidth->Position;
    Styl Üt∞tce urΦuje v²pl≥ov² vzor p°i vypl≥ovßnφ tvar∙. P°eddefinovanΘ styly zahrnujφ plnou plochu, prßzdn² styl a r∙znΘ styly Ürafovßnφ. Pro zm∞nu stylu Üt∞tce, nastavφme jeho vlastnost Style na jednu z p°eddefinovan²ch hodnot: bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross nebo bsDiagCross. V naÜi aplikaci je sdφlenß obsluha udßlosti pro vÜech osm tlaΦφtek stylu Üt∞tce (obdobn∞ jako pro styl pera):
    void __fastcall TForm1::SetBrushStyle(TObject *Sender)
    {
      if (Sender == SolidBrush) Canvas->Brush->Style = bsSolid;
      else if (Sender == ClearBrush) Canvas->Brush->Style = bsClear;
      else if (Sender == HorizontalBrush) Canvas->Brush->Style = bsHorizontal;
      else if (Sender == VerticalBrush) Canvas->Brush->Style = bsVertical;
      else if (Sender == FDiagonalBrush) Canvas->Brush->Style = bsFDiagonal;
      else if (Sender == BDiagonalBrush) Canvas->Brush->Style = bsBDiagonal;
      else if (Sender == CrossBrush) Canvas->Brush->Style = bsCross;
      else if (Sender == DiagCrossBrush) Canvas->Brush->Style = bsDiagCross;
    }
    Barva Üt∞tce urΦuje barvu v²pln∞. P°i jejφ zm∞n∞ m∞nφme hodnotu vlastnosti Üt∞tce Color. V naÜi aplikaci zm∞nu barvy Üt∞tce vy°eÜφme obdobn∞ jako zm∞nu barvy pera. Obsluha stisku tlaΦφtka ColorBrush je tvo°ena p°φkazy:
    ColorDialog1->Color = Canvas->Brush->Color;
    if (ColorDialog1->Execute())Brush->Color = ColorDialog1->Color;
    Nynφ ji₧ m∙₧eme kreslit r∙znΘ tvary, m∞nit jejich barvy, zadßvat v²pl≥ovΘ vzory apod. VyzkouÜejte.
  5. Dßle se budeme zab²vat stavov²m °ßdkem. P°esto₧e m∙₧eme k vytvo°enφ stavovΘho °ßdku vyu₧φt komponentu Panel, je jednoduÜÜφ pou₧φt p°φmo komponentu StatusBar. Tato komponenta nßm umo₧nφ rozd∞lit stavov² °ßdek na n∞kolik textov²ch oblastφ. K vytvo°enφ stavov²ch panel∙ na stavovΘm °ßdku pou₧ijeme Editor stavovΘho °ßdku a p°idßme k≤d pro aktualizaci jednotliv²ch stavov²ch panel∙. M∙₧eme takΘ urΦit, jak zarovnßvat text na jednotliv²ch panelech. V naÜi aplikaci pou₧ijeme stavov² °ßdek k zobrazovßnφ sou°adnic poΦßtku ka₧dΘho prvku a sou°adnic aktußlnφ pozice myÜi. V naÜi aplikaci je na formulß° p°idanß komponenta StatusBar, nazvanß StatusBar1 a je rozd∞lena na dva panely. Dßle je p°idßn k≤d k obsluhßm udßlostφ, kterΘ aktualizujφ stavov² °ßdek. Nßsleduje text zm∞n∞n²ch obsluh udßlostφ:

  6. void __fastcall TForm1::FormMouseDown(TObject *Sender,
         TMouseButton Button, TShiftState Shift, int X, int Y)
    {
      Drawing = true;
      Canvas->MoveTo(X, Y);
      Origin = Point(X, Y);
      MovePt = Origin;
      TVarRec tempvar[2] = {X, Y};
      StatusBar1->Panels->Items[0]->Text =
        Format("Origin: (%d, %d)", tempvar, 2);
    }
    void __fastcall TForm1::FormMouseMove(TObject *Sender,
         TShiftState Shift, int X, int Y)
    {
      if (Drawing){
        DrawShape(Origin, MovePt, pmNotXor);
        MovePt = Point(X, Y);
        DrawShape(Origin, MovePt, pmNotXor);
      }
      TVarRec tempvar[2] = {X, Y};
      StatusBar1->Panels->Items[1]->Text =
        Format("Current: (%d, %d)", tempvar, 2);
    }
  7. ╚as, kdy kreslφme p°φmo na formulß° ji₧ minul. Mnohem Φast∞ji aplikace kreslφ na bitovΘ mapy, nebo¥ bitovΘ mapy jsou velmi flexibilnφ pro operace (jako je kopφrovßnφ, tisk nebo ulo₧enφ). Komponenta Image je komponenta, kterß m∙₧e obsahovat bitovou mapu a umo₧≥uje snadnΘ vlo₧enφ jednΘ nebo vφce bitov²ch map na formulß°. Bitovß mapa takΘ nemusφ mφt stejnou velikost jako formulß°; m∙₧e b²t menÜφ nebo v∞tÜφ.

  8. ╚asto aplikace pot°ebuje zobrazovat vφce informacφ, ne₧ se vejde do jistΘ oblasti. N∞kterΘ ovladaΦe (nap°. okna seznam∙) mohou automaticky rolovat sv²m obsahem. I jinΘ ovladaΦe (vΦetn∞ samotnΘho formulß°e) takΘ poskytujφ schopnost rolovßnφ. Builder obsluhuje tyto posuvnΘ oblasti ovladaΦem naz²van²m posuvnΘ okno. PosuvnΘ okno se podobß panelu, kter² m∙₧e obsahovat jinΘ ovladaΦe, ale posuvnΘ okno je normßln∞ neviditelnΘ. Jestli₧e ovladaΦe obsa₧enΘ v posuvnΘm okn∞ nejsou ve viditelnΘ oblasti okna, pak je automaticky zobrazen jeden nebo dva posuvnφky, umo₧≥ujφcφ rolovat oknem. K vytvo°enφ posuvnΘ oblasti, umφstφme ovladaΦ ScrollBox na formulß° a nastavφme jeho meze na oblast, se kterou chceme rolovat (Φasto to provedeme pomocφ vlastnosti Align). V naÜi aplikaci vytvo°φme posuvnou oblast zabφrajφcφ celou plochu formulß°e mezi paletou nßstroj∙ a stavov²m °ßdkem. Na formulß° je umφst∞na komponenta ScrollBox a jejφ vlastnost Align je nastavena na alClient.
    Pomocφ komponenty Image specifikujeme oblast na formulß°i, kterß m∙₧e obsahovat objekt obrßzku (nap°. bitovou mapu nebo metasoubor). Velikost obrßzku lze nastavit manußln∞ nebo vyu₧φt ovladaΦ Image k udr₧ovßnφ velikosti svΘho obrßzku p°i b∞hu aplikace. Jestli₧e p°edpoklßdßme, ₧e tento ovladaΦ bude schopen m∞nit svou velikost, pak nastavφme umφst∞nφ jeho levΘho hornφho rohu. V naÜi aplikaci je na formulß° p°idßna komponenta Image a jsou u nφ nastaveny tyto vlastnosti: Name na Image, AutoSize na true, Left na 0, Top na 0, Width na 200 a Height na 200. Kdy₧ umφstφme ovladaΦ Image, pak je bez obrßzku. Jestli₧e mß obsahovat n∞jak² obrßzek, m∙₧eme p°i nßvrhu nastavit jeho vlastnost Picture. OvladaΦ takΘ m∙₧e zavΘst sv∙j obrßzek ze souboru p°i b∞hu aplikace. Jestli₧e pot°ebujeme prßzdnou bitovou mapu pro kreslenφ, m∙₧eme ji vytvo°it p°i b∞hu aplikace. K vytvo°enφ prßzdnΘ bitovΘ mapy p°i spuÜt∞nφ aplikace vytvo°φme obsluhu udßlosti OnCreate pro formulß° a vytvo°en² objekt bitovΘ mapy p°i°adφme vlastnosti Picture->Graphic ovladaΦe Image.
    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
      TBitmap *Bitmap = new Graphics::TBitmap();
      Bitmap->Width = 200;
      Bitmap->Height = 200;
      Image->Picture->Graphic = Bitmap;
    }
    P°i°azenφ bitovΘ mapy vlastnosti Graphic obrßzku vytvß°φ vzßjemn² vztah bitovΘ mapy a objektu obrßzku. Bitovou mapu tedy nenφ nutno ruÜit, zruÜφ ji objekt obrßzku. M∙₧eme p°i°adit objektu obrßzku dalÜφ bitovou mapu a obrßzek uvolnφ starou bitovou mapu a p°evezme °φzenφ novΘ. Jestli₧e nynφ spustφme aplikaci, vidφme na klientskΘ oblasti formulß°e bφlou oblast reprezentujφcφ bitovou mapu. Jestli₧e klientskß oblast okna nem∙₧e zobrazit cel² obrßzek, jsou automaticky zobrazeny posuvnφky pomocφ nich₧ lze zobrazit zbytek obrßzku. Obrßzek ale nelze kreslit, nebo¥ kreslenφ stßle probφhß na formulß°i, kter² je nynφ p°ekryt posuvn²m oknem a komponentou Image. Pro kreslenφ je nutno nynφ pou₧φt plßtno ovladaΦe Image namφsto plßtna formulß°e. Nejsnadn∞ji to provedeme zm∞nou vÜech v²skyt∙ Canvas na Image->Canvas v naÜφ programovΘ jednotce p°i°azenΘ k formulß°i. Dßle musφme p°i°adit obsluhy udßlostφ myÜφ odpovφdajφcφm udßlostem ovladaΦe Image. V Inspektoru objektu zobrazφme udßlosti objektu Image a odpovφdajφcφm udßlostem p°i°adφme ji₧ existujφcφ obsluhy udßlostφ formulß°e FormMouseDown, FormMouseMove a FormMouseUp. P∙vodnφ obsluhy pro formulß° m∙₧eme zruÜit, ale nenφ to nutnΘ. Nynφ po spuÜt∞nφ aplikace ji₧ m∙₧eme kreslit, ale pouze na ovladaΦi Image. M∙₧eme takΘ skr²t nebo zobrazit paletu pera nebo paletu Üt∞tce a rolovat obrßzkem.
  9. Aplikace obsahuje takΘ nabφdku. Nabφdka obsahuje obvyklΘ volby. Obsluha volby File | Exit je tvo°ena p°φkazem:

  10. Close();
    Aplikaci m∙₧eme spustit a vyzkouÜet.
    Tisk obrßzku z aplikace Builderu je jednoduch². Musφme p°idat hlaviΦkov² soubor Printers.hpp do programovΘ jednotky formulß°e, kterß bude tisknout. Tento hlaviΦkov² soubor deklaruje objekt nazvan² Printer, kter² mß plßtno reprezentujφcφ tiÜt∞nou stranu. Obrßzek vytiskneme kopφrovßnφm obrßzku na plßtno tiskßrny. V naÜi aplikaci vytvo°φme nßsledujφcφ obsluhu udßlosti OnClick pro volbu File | Print:
    void __fastcall TForm1::Print1Click(TObject *Sender)
    {
        int BitmapInfoSize, BitmapImageSize;
        long DIBWidth, DIBHeight;
        PChar BitmapImage;
        Windows::PBitmapInfo BitmapInfo;
        Graphics::TBitmap *Bitmap;
        Printer()->BeginDoc();
        Bitmap = new Graphics::TBitmap();
        Bitmap->Assign(Image->Picture);
        GetDIBSizes(Bitmap->Handle, BitmapInfoSize, BitmapImageSize);
        BitmapInfo  = (PBitmapInfo) new char[BitmapInfoSize];
        BitmapImage = (PChar) new char [BitmapImageSize];
        GetDIB(Bitmap->Handle, 0, BitmapInfo, BitmapImage);
        DIBWidth  = BitmapInfo->bmiHeader.biWidth;
        DIBHeight = BitmapInfo->bmiHeader.biHeight;
        StretchDIBits(Printer()->Canvas->Handle,
                    0, 0, DIBWidth, DIBHeight,
                    0, 0, DIBWidth, DIBHeight,
                    BitmapImage, BitmapInfo,
                    DIB_RGB_COLORS, SRCCOPY);
        delete [] BitmapImage;
        delete [] BitmapInfo;
        delete Bitmap;
        Printer()->EndDoc();
    }
  11. Obrßzky existujφ pouze p°i b∞hu aplikace. ╚asto chceme pou₧φt stejn² obrßzek nebo chceme ulo₧it vytvo°en² obrßzek pro pozd∞jÜφ pou₧itφ. Komponenta Image usnad≥uje zavßd∞nφ obrßzku a jejich uklßdßnφ. Princip uklßdßnφ a zavßd∞nφ grafick²ch soubor∙ je stejn² jako u jin²ch soubor∙. Na formulß° tedy p°idßme komponenty OpenDialog a SaveDialog. K zavedenφ grafickΘho souboru do ovladaΦe Image volφme metodu LoadFromFile objektu Picture ovladaΦe Image. Obsluha udßlosti OnClick volby File | Open vypadß takto:

  12. void __fastcall TForm1::Open1Click(TObject *Sender)
    {
      if (OpenDialog1->Execute()){
        CurrentFile = OpenDialog1->FileName;
        Image->Picture->LoadFromFile(CurrentFile);
      }
    }
    Kdy₧ vytvo°φme nebo modifikujeme obrßzek, Φasto jej chceme ulo₧it do souboru pro pozd∞jÜφ pou₧itφ. Objekt obrßzku m∙₧e uklßdat grafiku v n∞kolika formßtech a v²vojß° aplikace m∙₧e vytvß°et a registrovat vlastnφ formßty grafick²ch soubor∙, kterΘ objekt obrßzku pak m∙₧e pou₧φt. K ulo₧enφ obsahu ovladaΦe Image do souboru volßme metodu SaveToFile objektu Picture ovladaΦe Image. Nßsledujφ obsluhy udßlostφ OnClick voleb File | Save a File | Save As:
    void __fastcall TForm1::Save1Click(TObject *Sender)
    {
      if (CurrentFile != EmptyStr){
        Image->Picture->SaveToFile(CurrentFile);
      }
      else{
       SaveAs1Click(Sender);
      }
    }
    void __fastcall TForm1::SaveAs1Click(TObject *Sender)
    {
      if (SaveDialog1->Execute()){
        CurrentFile = SaveDialog1->FileName;
        Save1Click(Sender);
      }
    }
    Obrßzek v ovladaΦi m∙₧eme kdykoli p°i b∞hu aplikace nahradit jin²m obrßzkem. Jestli₧e p°i°adφme novou grafiku k obrßzku, kter² ji₧ mß grafiku, pak novß grafika nahradφ existujφcφ. Vytvß°enφ novΘ grafiky je stejn² proces jako jsme pou₧ili p°i vytvß°enφ inicializaΦnφ grafiky (obsluha udßlosti OnCreate), ale musφme dßt u₧ivateli mo₧nost zvolit i jinou ne₧ implicitnφ velikost obrßzku. To snadno provedeme pomocφ dialogovΘho okna. NaÜe aplikace obsahuje dialogovΘ okno NewBMPForm s editaΦnφmi ovladaΦi WidthEdit a HeightEdit. Obsluha volby File | New je tvo°ena p°φkazy:
    void __fastcall TForm1::New1Click(TObject *Sender)
    {
      Graphics::TBitmap *Bitmap;
      NewBMPForm->ActiveControl = NewBMPForm->WidthEdit;
      NewBMPForm->WidthEdit->Text =
        IntToStr(Image->Picture->Graphic->Width);
      NewBMPForm->HeightEdit->Text =
        IntToStr(Image->Picture->Graphic->Height);
      if (NewBMPForm->ShowModal() != IDCANCEL){
        Bitmap = new Graphics::TBitmap();
        Bitmap->Width = StrToInt(NewBMPForm->WidthEdit->Text);
        Bitmap->Height = StrToInt(NewBMPForm->HeightEdit->Text);
        Image->Picture->Graphic = Bitmap;
        CurrentFile = EmptyStr;
      }
    }
    Je d∙le₧itΘ pochopit, ₧e p°i°azenφ novΘ bitovΘ mapy k vlastnosti Graphic objektu obrßzku, zp∙sobφ zruÜenφ existujφcφ bitovΘ mapy a vytvo°enφ vzßjemnΘho vztahu s novou.
  13. Schrßnku Windows m∙₧eme pou₧φt pro kopφrovßnφ a vklßdßnφ grafiky ve svΘ aplikaci nebo k v²m∞n∞ grafiky s jinou aplikacφ. Objekt schrßnky pracuje s r∙zn²mi typy informacφ, vΦetn∞ grafick²ch. D°φve ne₧ m∙₧eme pou₧φt objekt schrßnky ve svΘ aplikaci, musφme p°idat hlaviΦkov² soubor Clipbrd.hpp do jednotky, ve kterΘ chceme schrßnku pou₧φvat. M∙₧eme kopφrovat libovoln² obrßzek, vΦetn∞ obsahu ovladaΦe Image do schrßnky. Po vlo₧enφ do schrßnky je obrßzek p°φstupn² pro vÜechny aplikace Windows. Pro kopφrovßnφ obrßzku do schrßnky p°i°adφme obrßzek k objektu schrßnky pou₧itφm metody Assign. V naÜφ aplikaci je nßsledujφcφ obsluha volby Edit | Copy.

  14. void __fastcall TForm1::Copy1Click(TObject *Sender)
    {
      Clipboard()->Assign(Image->Picture);
    }
    Vyjmutφ grafiky do schrßnky se podobß kopφrovßnφ, s tφm, ₧e je jeÜt∞ nutno zruÜit kopφrovanou grafiku. Nejprve vytvo°φme kopii ve schrßnce a potom zruÜφme originßl. Nßsleduje obsluha volby Edit | Cut:
    void __fastcall TForm1::Cut1Click(TObject *Sender)
    {
     TRect ARect;
     Copy1Click(Sender);
     Image->Canvas->CopyMode = cmWhiteness;
     ARect = Rect(0, 0, Image->Width, Image->Height);
     Image->Canvas->CopyRect(ARect, Image->Canvas, ARect);
     Image->Canvas->CopyMode = cmSrcCopy;
    }
    Jestli₧e schrßnka obsahuje bitovou mapu, m∙₧eme ji vlo₧it do libovolnΘho objektu obrßzku, vΦetn∞ ovladaΦe Image nebo samotnΘho formulß°e. Pro vlo₧enφ grafiky ze schrßnky, volßme metodu schrßnky HasFormat k zjiÜt∞nφ, zda schrßnka obsahuje grafiku (pro test na grafiku p°edßme metod∞ parametr CF_BITMAP) a pokud schrßnka grafiku obsahuje, pak ji p°i°adφme. V naÜi aplikaci je nßsledujφcφ obsluha volby Edit | Paste:
    void __fastcall TForm1::Paste1Click(TObject *Sender)
    {
      Graphics::TBitmap *Bitmap;
      if (Clipboard()->HasFormat(CF_BITMAP)){
        Bitmap = new Graphics::TBitmap();
        try{
          Bitmap->Assign(Clipboard());
          Image->Canvas->Draw(0, 0, Bitmap);
          delete Bitmap;
        }
        catch(...){
          delete Bitmap;
        }
      }
    }
    Nynφ ji₧ se schrßnkou m∙₧eme pracovat b∞₧n²m zp∙sobem a lze ji tedy vyu₧φt pro p°enos obrßzk∙ mezi r∙zn²mi aplikacemi. NaÜe aplikace je hotova.
  15. Pokuste se aplikaci grafickΘho editoru doplnit n∞jakou dalÜφ Φinnostφ. Vytvo°te pro tuto aplikaci takΘ nßpov∞du.
11. Prßce s grafikou I