GrafickΘ aplikace ve Visual C++ (2.)


I p°es vÜechny nev²hody GDI, je ve Windows tak°ka vÜudyp°φtomnΘ. JakΘkoliv kreslenφ ve Windows je dφlem prßv∞ GDI. Myslφm, ₧e princip GDI je pot°eba alespo≥ ΦßsteΦn∞ chßpat pro ·plnΘ pochopenφ DirectDraw. Ve skuteΦnosti na tom nic nenφ. Pot°ebujete v∞d∞t, co jednotlivΘ funkce ve skuteΦnosti d∞lajφ.

2.1. Funkce OnDraw()

Funkce OnDraw() je jedna z nejd∙le₧it∞Üφch funkcφ GDI. VßÜ program jφ automaticky volß poka₧dΘ, kdy₧ chce p°ekreslit okno tzn. p°i zm∞n∞ velikosti, maximalizaci nebo minimalizaci okna atd. Jednß se o Φlenskou funkci t°φdy pohledu CView. P°ijφmß jeden parametr a to je prßv∞ ukazatel na kontext za°φzenφ (DC) vaÜeho okna. Funkce kontextu za°φzenφ zapouzd°uje jinß t°φda CDC. Pomocφ tohoto parametru m∙₧ete provßd∞t veÜkerΘ kreslenφ do okna. NejjednoduÜÜφ °eÜenφ je, ₧e zapφÜete vßÜ k≤d p°φmo do tΘto funkce, p°φpadn∞ si vytvo°φte vlastnφ funkci, kterß bude mφt jako parametr ukazatel na DC a budete ji volat z funkce OnDraw().

2.2. Jednoduch² p°φklad kreslenφ do okna

Vytvo°te si standardnφ projekt SDI (Single Document Interface) MFC pomocφ AppWizardu.
Najd∞te funkci OnDraw() ve t°φd∞ pohledu CView. VaÜe t°φda pohledu se samoz°ejm∞ jmenuje podle jmΘna projektu nap°. projekt Pepa bude mφt t°φdu pohledu CPepaView.

Funkce CPepaView::OnDraw() po vygenerovßni AppWizardem:

  void CPepaView::OnDraw(CDC* pDC)//ukazatel na kontext za°φzenφ vaÜeho okna
  {
    CGDIDoc* pDoc = GetDocument();//ukazatel na vßÜ dokument tzn. na CPepaDoc
    ASSERT_VALID(pDoc);//ov∞°enφ pDoc
    // TODO: add draw code for native data here

  }

P°epiÜte funkci nßsledovn∞:

  void CPepaView::OnDraw(CDC* pDC)
  {
     CGDIDoc* pDoc = GetDocument();
     ASSERT_VALID(pDoc);

     //deklarace promenych
    CRect client, user;
    CPen pen;

    //tato funkce vrati velikost okna pohledu
    GetClientRect(&client);

    // vytvori pero o urcite sirce a barve
    pen.CreatePen(PS_SOLID, 5, RGB(255,0,0));

    //od kazde souradnice odectu 25 pixelu
    user.top = client.top + 25;
    user.left = client.left + 25;
    user.right = client.right - 25;
    user.bottom = client.bottom - 25;

    pDC->SelectObject(&pen); //vybere nase pero do kontextu zarizeni
    pDC->Rectangle(&user); // tato funkce nakresli obdelnik

    //napise text doprostred okna
    pDC->TextOut(client.right / 2, client.bottom / 2, "GDI v praxi");

  }

Program nakreslφ do okna Φerven² obdΘlnφk a doprost°ed napφÜe text. Do kontextu za°φzenφ v₧dy kreslφte prßv∞ vybran²m tzv. GDI objektem jako jsou pera, Üt∞tce, fonty, bitmapy atd. Tyto objekty jsou v MFC za prvΘ p°edem p°ipraveny jako Stock Objects a za druhΘ si je m∙₧ete vytvo°it samy, co₧ je samoz°ejm∞ b∞₧n∞jÜφ zp∙sob prßce z GDI objekty.

2.3. GDI objekty

GDI objekty zapouzd°uje n∞kolik t°φd (my si uvedeme jen ty nejb∞₧n∞jÜφ) :


Pero

CPen - t°φda, ze kterΘ se vytvo°φ pero o danΘm typu, Üφ°ce a barv∞. Perem kreslφme Φßry r∙znΘ tlouÜ¥ky a typu.

Postup vytvo°enφ pera :

  1. Vytvo°φte objekt typu CPen

  2. Zavolßte Φlenskou funkci t°φdy CPen::CreatePen()

Takto vypada deklarace funkce pro vytvo°enφ pera:
BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor);

  1. nPenStyle - styl pera m∙₧e b²t nap°φklad:

    • PS_SOLID - plnß Φßra

    • PS_DOT - teΦkovanß Φßra

    • PS_DASH - Φßrkovanß Φßra

    • PS_DASHDOT - Φerchovanß Φßra


  2. nWidth - Üφ°ka pera je celoΦφselnß hodnota v pixelech (v²Üe uvedenΘ typy per krom∞ PS_SOLID fungujφ pouze je-li Üφ°ka pera 1 pixel).

  3. crColor - barva pera. Tento parametr se p°edßvß pomocφ makra RGB, kterΘ p°ijφmß t°i hodnoty barev RGB (Red, Green, Blue) v rozsahu 0 - 255 nap°. kdy₧ napφÜete RGB(255,0,0) funkce vytvo°φ syt∞ ΦervenΘ pero.

Tento objekt jsme pou₧ili ve v²Üe uvedenΘm p°φkladu.


èt∞tec - Brush

CBrush - t°φda, kterß vytvo°φ Üt∞tec pro vykreslovßnφ velk²ch ploch v okn∞ libovolnou barvou nebo vzorem.

Postup vytvo°enφ Üt∞tce :

  1. Vytvo°φte objekt typu CBrush

  2. Zavolßte Φlenskou funkci t°φdy CBrush::CreateSolidBrush(). Funkce CreateSolidBrush() vytvo°φ Üt∞tec o jednΘ barv∞ tzn. ₧e mß jeden parametr, kter² se zadßvß podobn∞ jako u pera pomocφ makra RGB.

Font

CFont - t°φda, kterß vytvo°φ font pro psanφ do okna. M∙₧ete si vytvo°it zcela vlastnφ font, ale myslφm, ₧e spφÜe vyu₧ijete font∙, kterΘ jsou nainstalovanΘ ve Windows.

Postup vytvo°enφ fontu :

  1. Vytvo°φte objekt typu CFont

  2. Zavolßte Φlenskou funkci t°φdy CFont::CreatePointFont(), kterß mß nßsledujφcφ parametry :

    1. velikost fontu v desetinßch bodu tzn. pokud chcete pφsmo o velikosti 12 bod∙ musφte zadat tento parametr 120

    2. tvß° (face) fontu. Tento parametr je °et∞zec, kter² obsahuje jmΘno vybranΘho fontu tzn. pokud chcete Arial dosadφte "Arial" nebo "Times New Roman" pro Times New Roman. Pokud nenφ vßmi vybranΘ pφsmo ve Windows program pou₧ije standardnφ pφsmo.



DalÜφmi GDI objekty jsou nap°φklad CBitmap, CPalette nebo CRgn.

2.4. T°φda CDC

PotΘ, co si vytvo°φte sv∙j GDI objekt musφte ho vybrat do kontextu za°φzenφ vaÜeho okna. To obstarß funkce t°φdy CDC::SelectObject(), kterß p°ijφmß ukazatel na vßÜ GDI objekt. Od tΘto chvφle se bude kreslit vaÜφm perem nebo Üt∞tcem a psßt vaÜφm fontem. D∙le₧itΘ je, ₧e m∙₧e b²t vybrßn jen jeden objekt. Pokud tedy zavolßte opakovan∞ tuto funkci, p°edchozφ objekt se vyjme a vlo₧φ se jin². Funkce SelectObjekt() vracφ ukazatel p°edeÜl² vybran² objekt GDI.

T°φda CDC obsahuje velkΘ mno₧stvφ funkcφ pro kreslenφ, tak₧e je nemohu vÜechny popsat.

Funkce pro objekt CPen:

CPoint MoveTo( int x, int y );
CPoint MoveTo( POINT point );

Tyto dv∞ funkce pouze p°esouvajφ aktußlnφ pozici odkud se bude p°φÜt∞ kreslit. Vracφ p°edeÜlou pozici.

BOOL LineTo( int x, int y );
BOOL LineTo( POINT point );

Tyto dv∞ funkce kreslφ do okna prßv∞ vybran²m perem Φßru. Kreslφ se z aktußlnφ pozice p°edem nastavenΘ funkcφ MoveTo() na pozici urΦenou parametry. Aktußlnφ sou°adnice se p°esouvß tam, kde skonΦφ pero s kreslenφm. Vracφ nenulovou hodnotu pokud je ·sp∞Ünß jinak 0.


Poznßmka: VÜimn∞te si, ₧e ka₧dß funkce mß dv∞ varianty, to umo₧≥uje C++ dφky p°et∞₧ovßnφ funkcφ (overloading). Vidφte, ₧e prvnφ varianta p°ijφmß jednoduchΘ typy, zatφmco druhß varianta objekt POINT respektive RECT. To jsou objekty Win32 API. Ekvivalentnφ objekt v MFC je CPoint respektive CRect. Tento objekt za prvΘ uchovßvß informaci o sou°adnici bodu respektive obdΘlnφku a za druhΘ obsahuje mnoho Φlensk²ch funkcφ, kterΘ podstatn∞ zjednoduÜujφ prßci programßtora.



BOOL Rectangle( int x1, int y1, int x2, int y2);
BOOL Rectangle( LPRECT lpRect);

Tyto funkce nakreslφ obdΘlnφk do okna vybran²m perem. Jako parametry m∙₧ete zadat Φty° sou°adnice tzn. hornφ lev² roh a dolnφ prav² roh nebo p°edßte ukazatel na objekt typu CRect respektive RECT. Vracφ nenulovou hodnotu pokud je ·sp∞Ünß jinak 0.

BOOL Ellipse ( int x1, int y1, int x2, int y2 );
BOOL Ellipse ( LPRECT lpRect );

Tyto funkce kreslφ obecn∞ elipsu, ale dß se s nφ samoz°ejm∞ nakreslit i kru₧nice. Mß Φty°i parametry, kterΘ jsou vlastn∞ stejnΘ jako u p°edeÜlΘ funkce. Vracφ nenulovou hodnotu pokud je ·sp∞Ünß jinak 0.

Funkce pro objekt CBrush

BOOL FillRect ( LPRECT lpRect, CBrush * pBrush );

Tato funkce trochu popφrß, co jsme si °ekli o vklßdßnφ objekt∙, proto₧e p°ijφmß parametr typu CBrush, co₧ je jak jist∞ vφte GDI objekt. No nevφm, jak to v²vojß°i MFC mysleli. Ka₧dopßdn∞ tato funkce funguje tak, ₧e vyplnφ obdΘlnφkovou oblast prßv∞ tφm Üt∞tcem, kter² je zadßn jako parametr a ne tφm, kter² je vybrßn v DC. Prvnφ parametr je ukazatel na objekt typu CRect respektive RECT.

BOOL FloodFill ( int x, int y , COLORREF crColor);

Tato funkce je velmi podobnß funkci ze starΘho Pascalu. ZaΦne vypl≥ovat plochu od urΦenΘho bodu, dokud nenarazφ barvu urΦenou parametrem crColor. Prvnφ dva parametry jsou ten bod a druhy ta barva, kterß se op∞t zadßvß pomocφ makra RGB (viz v²Üe). Vypl≥uje prßv∞ vybran²m Üt∞tcem. Vracφ nenulovou hodnotu pokud je ·sp∞Ünß jinak 0.

Funkce pro objekt CFont

BOOL TextOut (int x, int y, CString& str );

Tato funkce napφÜe text v bod∞ o sou°adnicφchx a y. Samotn² text je ulo₧en ve t°etφm parametru typu CString respektive referenci na CString. PφÜe se prßv∞ vybran²m fontem a nßvratovß hodnota je stejnß jako ve vÜech p°edchozφch p°φpadech.

T°φda CDC mß spoustu dalÜφch funkcφ. Pokud byste m∞li n∞jak² specißlnφ zßjem, staΦφ napsat.

2.5. P°φklad

P°ipravil jsem pro vßs jednoduch² p°φklad, kter² pou₧ije vÜechny v²Üe popsanΘ funkce. Je to standardnφ aplikace MFC AppWizard [exe]. P°esn² postup, jak vytvo°it tento typ aplikace najdete ve t°etφm kurzu tohoto dφlu a vy akorßt upravφte funkci OnDraw(). Tento p°φklad si m∙₧ete stßhnout z CD zde nebo v sekci Downloads.

void CGDIView::OnDraw(CDC* pDC)
{
    CGDIDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    //
    // Procvicujeme funkce GDI
    CRect rcClient;
    // Ulozime si velikost okna
    GetClientRect(&rcClient);
    //
    // 1. Vytvorme si objekt pera CPen
    CPen penBlue;
    penBlue.CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
    // 2. Vytvorme si objekt stetce CBrush
    CBrush brushRed, brushGreen;
    brushRed.CreateSolidBrush(RGB(255, 0, 0));
    brushGreen.CreateSolidBrush(RGB(0, 255, 0));
    // 3. Do tretice si vytvorime font CFont
    CFont fontTimes;
    fontTimes.CreatePointFont(120, "Times New Roman");
    //
    // Vybereme pero
    pDC->SelectObject(penBlue);
    // Nyni muzeme kreslit modrym perem
    // 1. Vytvorime diagonalni caru
    pDC->MoveTo(0, 0);
    pDC->LineTo(rcClient.right, rcClient.bottom);
    // 2. Nakreslime obdelnik
    pDC->Rectangle(rcClient.left + 25, rcClient.top + 25,
        rcClient.right - 25, rcClient.bottom - 25);
    // 3. Nakreslime elipsu uprostred okna

    pDC->Ellipse(rcClient.left + 50, rcClient.top + 50,
        rcClient.right - 50, rcClient.bottom - 50);
    // 4. Pouzijeme funkci FillRect() k vybarveni obdelnicku
    // Vsimnete si, ze nevybirame stetec!!!
    pDC->FillRect(CRect(150, 150, 200, 200), &brushGreen);
    //
    // Nyni jiz musime vybrat stetec do DC
    pDC->SelectObject(brushRed);
    // 5. Pouzijeme funkci FloodFill() k vybarveni obdelnicku
    pDC->FloodFill(30, 30, RGB(0, 0, 255));
    //
    // 6. Nakonec vybereme font do DC a napiseme text doprostred okna
    pDC->SelectObject(fontTimes);
    pDC->TextOut(rcClient.right / 2, rcClient.bottom / 2, "GDI v praxi");
    //
}


Poznßmka:

  • Zkuste si zmenÜit Φi zv∞tÜit okno. VÜimn∞te si, ₧e obsah okna se nehezky p°ekresluje poka₧dΘ, kdy₧ zm∞nφte velikost okna. To je dßno tφm, ₧e funkce OnDraw() je volßna poka₧dΘ, kdy₧ se mß okno p°ekreslit a takΘ samoz°ejm∞ tφm, ₧e GDI je pomalΘ.

  • Jak vidφte u funkce FillRect(), nenφ pot°eba vybφrat ₧ßdn² Üt∞tec, proto₧e se k vybarvenφ pou₧ije Üt∞tec, kter² je dßn v druhΘm parametru.

  • Vzßp∞tφ ale vidφte, ₧e u funkce FloodFill() ji₧ Üt∞tec vybrat musφme, jinak se pou₧ije tzv. NULL BRUSH, kter² nenakreslφ v∙bec nic.

  • Text, kter² mß b²t uprost°ed okna, vlastn∞ nenφ p°esn∞ uprost°ed. Zkuste program upravit tak, aby text byl poka₧dΘ uprost°ed. Je nutnΘ do sou°adnic textu zahrnout takΘ velikost samotnΘho textu.


Takto vypadß okno naÜφ aplikace:



2.6. Zßv∞r

Tato Φßst vßs tedy seznßmila s ·pln²mi zßklady GDI a m∞li byste si alespo≥ n∞co z toho pamatovat, aΦkoliv to v DirectDraw p°φmo nepou₧ijeme. V DirectDraw budeme tu a tam pou₧φvat kontexty za°φzenφ, ale to uvidφte a₧ v p°φÜtφ lekci. V p°φÜtφ lekci u₧ zaΦneme skuteΦnΘ DirectDraw. Pokud byste m∞li n∞jakΘ specißlnφ po₧adavky nebo cht∞li poradit, m∙₧ete mi napsat.

T∞Üφm se p°φÜt∞ nashledanou.

Ji°φ Formßnek