Radek ChalupaČlánkyUkázky kóduTipy a trikyAktualityŠkolení a konzultaceVývoj softwareFreewareKontakt

Kreslení plošných objektů. Štětce.  17.1.2002

Zatím jsme se zabývali pouze takříkajíc čárovými grafickými objekty. V tomto pokračování se seznámíme s tím, jak kreslit plošné objekty a definovat vlastnosti jejich výplně pomocí štětců.

Geometrické útvary, které budeme dnes kreslit, budou mít definovány 2 typy "vlastností". Čáry tvořící jejich okraj, budou mít vlastnosti definované nám již známými pery a výplně štětci (brush), se kterými se seznámíme dnes. Princip použití štětců je stejný jako per. Nejdříve si jednou z příslušných funkcí vytvoříme objekt typu štětec (handle HBRUSH), ten pak vybereme pomocí funkce SelectObject do kontextu zařízení (HDC) a poté budou mít nakreslené grafické objekty výplň tvořenou aktuálně vybraným štětcem.

Nejjednodušším tvarem je obyčejný obdélník. Pokud chceme nakreslit obdélník, jehož okraj je kreslený aktuálně vybraným perem a výplň je tvořená aktuálně vybraným štětcem, použijeme funkci Rectangle:

BOOL Rectangle(
  HDC hdc,         // handle kontextu zařízení
  int nLeftRect,   // x-souřadnice levého horního rohu
  int nTopRect,    // y-souřadnice levého horního rohu
  int nRightRect,  // x-souřadnice pravého dolního rohu
  int nBottomRect  // y-souřadnice pravého dolního rohu
);

Dalším základním tvarem je elipsa nebo kružnice jako zvláštní případ elipsy, kterou kreslíme pomocí funkce Ellipse:

BOOL Ellipse(
  HDC hdc,        // handle kontextu zařízení
  int nLeftRect,  // x-souřadnice levého horního rohu opsaného obdélníka
  int nTopRect,   // y-souřadnice
  int nRightRect, // x-souřadnice pravého dolního rohu opsaného obdélníka
  int nBottomRect // y-souřadnice
);

Uveďme si zde ještě jeden plošný útvar kterým je obdélník (čtverec) se zaoblenými rohy, kreslený funkcí RoundRect:

BOOL RoundRect(
  HDC hdc,         // handle kontextu zařízení
  int nLeftRect,   // x-souřadnice levého horního rohu opsaného obdélníka
  int nTopRect,    // y-souřadnice
  int nRightRect,  // x-souřadnice pravého dolního rohu opsaného obdélníka
  int nBottomRect, // y-souřadnice
  int nWidth,      // šířka elipsy tvořící zaoblené rohy
  int nHeight      // výška elipsy tvořící zaoblené rohy
);

Další plošné geometrické objekty, resp. funkce pro jejich kreslení jsou samozřejmě popsány v dokumentaci. Pro nás je nyní důležité seznámit se se štětci tvořícími výplň plošných objektů. Nejjednodušším případem je štětec tvořený jednou barvou, který vytvoříme funkcí CreateSolidBrush:

HBRUSH CreateSolidBrush(
  COLORREF crColor   // definice barvy
);

Handle typu HBRUSH vrácený touto funkcí pak vybereme již známou funkcí SelectObject do kontextu zařízení (HDC) a všechny další kreslené plošné objekty pak budou mít výplň tvořenou tímto štětcem. Ukážeme si příklad, ve kterém se současně ještě vrátíme k perům, přesněji řečeno k demonstraci stylu pera PS_INSIDEFRAME. Tento styl pera určuje, že pokud je kreslen obrazec, který definujeme opsaným obdélníkem (jako výše zmíněná elipsa/kružnice) a pero má šířku větší než 1 pixel, je obrazec nakreslen tak že se celý vejde dovnitř tohoto obdélníka. Bez tohoto stylu k okrajům obdélníka přiléhá střed čáry a tedy polovina šířky čáry pera je mimo tyto hranice. Podívejme se na příklad, který toto demonstruje:

win-api-17-1

V obou případech (jak uvidíte z výpisu kódu) je kružnice (kreslená funkcí Ellipse) definována stejným (rozměrově) opsaným obdélníkem. Rozdíl je ve vybraném peru. Pero použité pro levý obrázek má ve stylu příznak PS_INSIDEFRAME, tj je vytvořené takto:

hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, 20, 0x00FF8080);

Současně je ukázán příklad obdélníka kresleného systémovým černým perem a vyplněného systémovým bílým štětcem. Je to ukázka použítí funkce GetStockObject:

HGDIOBJ GetStockObject(
  int fnObject   // typ objektu
);

Touto funkcí můžeme získat již existující handle na některý ze systémových objektů. Jejich úplný seznam naleznete v dokumentaci této funkce. Zbytek kódu pak ukazuje vytvoření spojitého pera, a jeho použití jako výplň kružnice. Zde je tedy opis kódu, volaného z handleru zprávy WM_PAINT, realizujícího výše uvedený obrázek:

void InsideFrameDemo(HDC hdc)
{
  HPEN hPen;
  HBRUSH hBrush;
  hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, 20, 0x00FF8080);
  hBrush = CreateSolidBrush(0x0080FFFF);
  SelectObject(hdc, GetStockObject(BLACK_PEN));
  Rectangle(hdc, 15, 15, 115, 115);
  SelectObject(hdc, hPen);
  SelectObject(hdc, hBrush);
  Ellipse(hdc, 15, 15, 115, 115);
  SelectObject(hdc, GetStockObject(BLACK_PEN));
  DeleteObject(hPen);
  SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  Rectangle(hdc, 140, 15, 240, 115);
  hPen = CreatePen(PS_SOLID, 20, 0x00FF8080);
  SelectObject(hdc, hPen);
  SelectObject(hdc, hBrush);
  Ellipse(hdc, 140, 15, 240, 115);
  SelectObject(hdc, GetStockObject(WHITE_PEN));
  DeleteObject(hPen);
  DeleteObject(hBrush);
}

Dále si ještě ukážeme příklad štětce, tvořeného mřížkou zvolené barvy a typu. K tomu nám slouží funkce CreateHatchBrush:

HBRUSH CreateHatchBrush(
  int fnStyle,      // styl mřížky
  COLORREF clrref   // barva čar mřížky
);

Parametr fnStyle určuje typ mřízky, může mít jednu z hodnot, které jsou vypsány na následujícím obrázku, z něhož je nejlépe patrný jejich význam:

win-api-17-3

Kód toto realizující vypadá následovně:

void ShowBrush(HDC hdc, int Style, int x, int y, LPCTSTR lpText)
{
  RECT rect;
  rect.left = x;
  rect.top = y;
  rect.right = rect.left + 140;
  rect.bottom = rect.top + 80;
  HBRUSH hb = CreateHatchBrush(Style, 0x00A00000);
  SelectObject(hdc, hb);
  FillRect(hdc, &rect, hb);
  DrawText(hdc, lpText, lstrlen(lpText), &rect,
    DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  DeleteObject(hb);
}

void OnPaint(HDC hdc)
{
  ShowBrush(hdc, HS_BDIAGONAL, 10, 10, "HS_BDIAGONAL");
  ShowBrush(hdc, HS_CROSS, 160, 10, "HS_CROSS");
  ShowBrush(hdc, HS_DIAGCROSS, 310, 10, "HS_DIAGCROSS");
  ShowBrush(hdc, HS_FDIAGONAL, 10, 100, "HS_FDIAGONAL");
  ShowBrush(hdc, HS_HORIZONTAL, 160, 100, "HS_HORIZONTAL");
  ShowBrush(hdc, HS_VERTICAL, 310, 100, "HS_VERTICAL");
}

Na závěr ještě ukázku použití funkce Rect  a RoundRect, opět ve spojení s mřížkovaným štětcem a vlastním perem:

win-api-17-2

Kód tohoto kreslení:

void HatchBrush(HDC hdc)
{
  HBRUSH hBrush, hbOld;
  HPEN hPen, hpOld;
  hBrush = CreateHatchBrush(HS_CROSS, 0x000000A0);
  hPen = CreatePen(PS_SOLID, 8, 0x00D00000);
  hbOld = (HBRUSH)SelectObject(hdc, hBrush);
  hpOld = (HPEN)SelectObject(hdc, hPen);
  Rectangle(hdc, 10,10, 180, 120);
  SelectObject(hdc, hbOld);
  DeleteObject(hBrush);
  hBrush = CreateHatchBrush(HS_DIAGCROSS, 0x0000A000);
  SelectObject(hdc, hBrush);
  RoundRect(hdc, 10,140, 180, 230, 50, 50);
  SelectObject(hdc, hpOld);
  DeleteObject(hPen);
}

Doprovodný projekt je ke stažení zde: win_api_17.zip


Copyright © 2019 - Radek Chalupa