Geometrická pera

V tomto článku si řekneme více o některých složitějších perech (pens), jako jsou tzv. geometrická pera a o jejich dalších vlastnostech.
Na prvním obrázku vidíte ukázku geometrického pera tvořeného bitmapou s různým způsobem zakončení. Všechny 3 „obrázky“ jsou vytvořeny pomocí tří volání funkce LineTo, tedy jedná se o 3 napojené čáry s tím, že do kontextu zařízení bylo vybráno pero, jehož vytvoření si v tomto článku popíšeme.

Klepněte pro větší obrázek

Jak na to

Pro vytváření "složitějších" per slouží funkce

HPEN ExtCreatePen(
  DWORD dwPenStyle, // styl pera
  DWORD dwWidth, // "délka" pera
  CONST LOGBRUSH *lplb, // vlastnosti štětce
  DWORD dwStyleCount, // délka vlastního stylu
  CONST DWORD *lpStyle // vlastní styl
);

Tato funkce, jak už název napovídá, rozšiřuje možnosti funkce CreatePen. Ukážeme si, jak vytvořit tzv. geometrické pero, které bude tvořené štětcem (HBRUSH), který vytvoříme na základě bitmapy, jako tzv. "pattern brush". Geometrické pero má v parametru dwPenStyle vlastnost PS_GEOMETRIC s tím, že styl může být kombinován s dalšími upřesňujícími vlastnostmi. Řekněme si nedříve o dvou dalších vlastnostech pera - zakončení a vlastnosti "uvnitř rámce" (inside frame).

Efekt vlastnosti "uvnitř rámce" je nejlépe zřejmý z následující ukázky, kde v obou případech je modrá elipsa (kružnice) krelsena pomocí GDI funkce Ellipse se stejnými rozměry, definovanými obdélníkem (vyplněným bílou barvou). Pokud má pero, kterým je elipsa kreslena vlastnost PS_INSIDEFRAME, přizpůsobí se rozměry elipsy tak, aby vždy přesně zapadala do definovaného "opsaného" obdélníka. V opačném případě (bez uvedení vlastnosti PS_INSIDEFRAME) obdélník opisuje střed pera, a podle tloušťky pera jeho část zasahuje mimo definovaný obdélník.

Klepněte pro větší obrázek

celý kód realizující ukázku je umístěn v handleru zprávy WM_PAINT dialogu:

void CInsideFrameDlg::OnPaint()
{
  CPaintDC dc(this);
  HPEN hpen;
  LOGBRUSH lb;
  lb.lbStyle = BS_SOLID;
  lb.lbColor = 0x00FF8080;
  lb.lbHatch = 0;
  hpen = ExtCreatePen(PS_GEOMETRIC | PS_INSIDEFRAME, 40, &lb, 0, NULL);
  SelectObject(dc.m_hDC, GetStockObject(WHITE_BRUSH));
  SelectObject(dc.m_hDC, GetStockObject(WHITE_PEN));
  dc.Rectangle(15, 25, 180, 190);
  SelectObject(dc.m_hDC, hpen);
  dc.Ellipse(15, 25, 180, 190);
  SelectObject(dc.m_hDC, GetStockObject(WHITE_PEN));
  DeleteObject(hpen);
  dc.Rectangle(230, 25, 395, 190);
  hpen = ExtCreatePen(PS_GEOMETRIC, 40, &lb, 0, NULL);
  SelectObject(dc.m_hDC, hpen);
  dc.Ellipse(230, 25, 395, 190);
  SelectObject(dc.m_hDC, GetStockObject(WHITE_PEN));
  DeleteObject(hpen);
}
Vlastnost "zakončení" (ENDCAP) je již naznačena na prvním obrázku. Aby byla zcela zřejmá, podívejte se na následující obrázek, který ukazuje 3 čáry stejné délky kreslené žlutým geometrickým perem funkcí LineTo se třemi různými vlastnostmi zakončení:

Klepněte pro větší obrázek

  • PS_ENDCAP_ROUND - zakončení je tvořeno kružnicí se středem v koncovém bodu čáry a průměrem stejným jako "šírka" pera
  • PS_ENDCAP_SQUARE - zakončení je tvořeno čtvercem se středem v koncovém bodu čáry a stranou o délce stejné jako "šírka" pera.
  • PS_ENDCAP_FLAT - čára je ukončena v bodě určeném příslušnou GDI funckí (např. LineTo)
vše je opět realizováno v handleru WM_PAINT:

void CEndCapDlg::OnPaint()
{
  CPaintDC dc(this); // device context for painting
  HPEN hpen;
  LOGBRUSH lb;
  lb.lbStyle = BS_SOLID;
  lb.lbColor = 0x0080FFFF;
  lb.lbHatch = 0;
  hpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_ROUND, 40, &lb, 0, NULL);
  HPEN hpOld = (HPEN)::SelectObject(dc.m_hDC, hpen);
  dc.MoveTo(50, 50);
  dc.LineTo(200, 50);
  SelectObject(dc.m_hDC, GetStockObject(BLACK_PEN));
  dc.MoveTo(50, 50);
  dc.LineTo(200, 50);
  DeleteObject(hpen);
  hpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_SQUARE, 40, &lb, 0, NULL);
  SelectObject(dc.m_hDC, hpen);
  dc.MoveTo(50, 100);
  dc.LineTo(200, 100);
  SelectObject(dc.m_hDC, GetStockObject(BLACK_PEN));
  dc.MoveTo(50, 100);
  dc.LineTo(200, 100);
  DeleteObject(hpen);
  hpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT, 40, &lb, 0, NULL);
  SelectObject(dc.m_hDC, hpen);
  dc.MoveTo(50, 150);
  dc.LineTo(200, 150);
  SelectObject(dc.m_hDC, GetStockObject(BLACK_PEN));
  dc.MoveTo(50, 150);
  dc.LineTo(200, 150);
  SelectObject(dc.m_hDC, hpOld);
  DeleteObject(hpen);
}

Nyní se již dostáváme k peru tvořeném bitmapou. pro tento případ musíme ve struktuře LOGBRUSH uvést jako lbStyle hodnotu BS_PATTERN a prvek lbHatch pak určuje handle bitmapy, která má tvořit štětec definující pero.

Nyní již konkrétně. Třída hlavního okna má členskou proměnnou m_hbitmap, což je handle bitmapy (HBITMAP), získané ze zdrojů. Pozadí celého okna je nastaveno pomocí funkce SetClassLongPtr nastavením handle na štětec pozadí:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
  return -1;
  m_hbitmap = LoadBitmap(AfxGetInstanceHandle(),
    MAKEINTRESOURCE(IDB_BITMAP_PEN));
  SetClassLongPtr(m_hWnd, GCLP_HBRBACKGROUND,
  (LONG)(HBRUSH)CreatePatternBrush(LoadBitmap(AfxGetInstanceHandle(),
    MAKEINTRESOURCE(IDB_BITMAP_BACK))));
  return 0;
}

V ukázkovém příkladě je pak funkce pro vytvoření "bitmapového" pera s parametry určujícími dvě výše zmíněné upřesňující vlastnosti:

HPEN CMainHPEN CMainFrame::CreateBitmapPen(BOOL InsideFrame, DWORD dwEndCap)
{
  if ( m_hbitmap == NULL )
    return NULL;
  LOGBRUSH lb;
  lb.lbStyle = BS_PATTERN;
  lb.lbColor = 0x00;
lb.lbHatch = (LONG)m_hbitmap;
  DWORD dwStyle = PS_GEOMETRIC;
  if ( InsideFrame )
    dwStyle |= PS_INSIDEFRAME;
  return ExtCreatePen(dwStyle | dwEndCap, 30, &lb, 0, NULL);
}

Pak už zbývá je kreslit v handleru WM_PAINT abychom dostali výsledek, který je na prvním obrázku:

void CMainFrame::OnPaint()
{
  CPaintDC dc(this); // device context for painting
  if ( m_hbitmap == NULL )
    return;
  HPEN hpen, hpOld;
  int yStart = 30;
  dc.SetBkMode(TRANSPARENT);
  hpen = CreateBitmapPen(TRUE, PS_ENDCAP_ROUND);
  hpOld = (HPEN)SelectObject(dc.m_hDC, hpen);
  dc.MoveTo(30, yStart+50);
  dc.LineTo(30, yStart);
  dc.LineTo(250, yStart);
  dc.LineTo(250, yStart+50);
  SelectObject(dc.m_hDC, hpOld);
  DeleteObject(hpen);
  dc.TextOut(60, yStart+30, "PS_ENDCAP_ROUND");
  yStart += 100;
  hpen = CreateBitmapPen(TRUE, PS_ENDCAP_SQUARE);
  hpOld = (HPEN)SelectObject(dc.m_hDC, hpen);
  dc.MoveTo(30, yStart+50);
  dc.LineTo(30, yStart);
  dc.LineTo(250, yStart);
  dc.LineTo(250, yStart+50);
  SelectObject(dc.m_hDC, hpOld);
  DeleteObject(hpen);
  dc.TextOut(60, yStart+30, "PS_ENDCAP_SQUARE");
  yStart += 100;
  hpen = CreateBitmapPen(TRUE, PS_ENDCAP_FLAT);
  hpOld = (HPEN)SelectObject(dc.m_hDC, hpen);
  dc.MoveTo(30, yStart+50);
  dc.LineTo(30, yStart);
  dc.LineTo(250, yStart);
  dc.LineTo(250, yStart+50);
  SelectObject(dc.m_hDC, hpOld);
  DeleteObject(hpen);
  dc.TextOut(60, yStart+30, "PS_ENDCAP_FLAT");
}
Ukázkový projekt si můžete stáhnout zde geometric_pen.zip (66,7 kB)

Diskuze (11) Další článek: Petice za uvolnění zdrojových kódů OS/2

Témata článku: Software, Programování, Brush, Pero, GEO, CFR, Peru


Určitě si přečtěte

Google vymyslel technologii superpřesného GPS. Už ji podporuje Pixel 5 a dorazí i na ostatní telefony

Google vymyslel technologii superpřesného GPS. Už ji podporuje Pixel 5 a dorazí i na ostatní telefony

** Kvalita GPS ve městech občas stojí za starou bačkoru ** Mohou za to odrazy signálu od okolních budov ** Google má jejich 3D model, a tak spolupracuje s výrobci GPS čipů

Jakub Čížek | 40

Jakub Čížek
NavigaceTechnologieGoogle
26 užitečných rozšíření pro Chrome: Naučte prohlížeč nové věci

26 užitečných rozšíření pro Chrome: Naučte prohlížeč nové věci

** Prohlížeč Chrome obsahuje širokou škálu funkcí, neumí ale všechno ** Jeho schopnosti můžete rozšířit pomocí rozšíření ** Vybrali jsme pro vás zajímavé a užitečné doplňky

Karel Kilián | 44

Karel Kilián
Doplňky do prohlížečeChromeProhlížeče
Jak v prohlížeči vypnout oznámení zasílaná webovými stránkami

Jak v prohlížeči vypnout oznámení zasílaná webovými stránkami

** Obtěžují vás neustálé dotazy webů, zda chcete zobrazovat oznámení? ** Můžete je zakázat, a to jak kompletně, tak i pro jednotlivé stránky ** Připravili jsme návody pro Chrome, Firefox, Edge a Operu

Karel Kilián | 11

Karel Kilián
Jak na InternetTipyProhlížeče
Vybrali jsme 12 programovatelných hraček a stavebnic pro děti a jejich rodiče

Vybrali jsme 12 programovatelných hraček a stavebnic pro děti a jejich rodiče

** Získejte děti pro matematiku a základy techniky ** Kupte jim hračku nebo stavebnici, které vdechnou vlastní život ** Vybrali jsme stavebnice pro malé caparty i budoucí experty

Jakub Čížek | 10

Jakub Čížek
Stavebnice
Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

** Kde jsou ty doby, kdy měl skoro každý doma Photoshop ** Photoshop a Premiere Pro od kamaráda nebo z warezu ** Dnes už to nemá smysl, existuje totiž hromada laciných alternativ

Jakub Čížek | 90

Jakub Čížek
Grafický editorStřih videa

Aktuální číslo časopisu Computer

Jak prodloužit výdrž notebooku

Velké testy: gamepady a inkoustové tiskárny

Důkladný test Sony Playstation 5