Windows Programming/GDI and Drawing

From Wikibooks, open books for an open world
Jump to navigation Jump to search

This page of the Windows Programming book is a stub. You can help by expanding it.

This page will talk about graphics and drawing using the windows GDI libraries.

Device Contexts[edit]

What's in? And their defaults:

GDI objects (one per type) Windows version Set function Get function
Pen Zero-width black pen (means 1 pixel width on any scaling) 2 SelectObject (SelectPen, SelectBrush, SelectFont) GetCurrentObject
Brush White solid brush 2
Font System default font 2
Palette System default palette (Notes below) 3 SelectPalette
Color space ? 4 SetColorSpace
Destination bitmap (not for Metafile contexts) depends on which function creates the DC 2 SelectObject (SelectBrush)
Clipping Region depends on which function creates the DC 2 GetClipRgn (GetClipBox)
Mapping mode, scaling and offset 1 unit = 1 pixel, origin = left/top 2 Get/Set MapMode, WindowOrgEx, WindowExtEx, ViewportOrgEx, ViewportExtEx
Transformation matrix (rotation, shearing, scaling, offset) Equality 4 SetWorldTransform, ModifyTransform GetWorldTransform
Text color, also used for black-and-white involving blt operations black 2 SetTextColor GetTextColor
Background color, used for text / hatch brush / dotted line background and some blt operations white 2 SetBkColor GetBkColor
Miter limit (clipping of sharp polygon corners) 10.0F (ten times the line width) 4 SetMiterLimit GetMiterLimit
Brush origin (for aligning a pattern brush) 0/0 2 SetBrushOrgEx GetBrushOrgEx
Enums and boolean switches
Enable advanced GDI functions No 4 SetGraphicsMode GetGraphicsMode
What's inside or outside a complex polygon (PolyFillMode) Alternate Rule 2 SetPolyFillMode GetPolyFillMode
Text alignment top/left 2 SetTextAlign GetTextAlign
Text / hatch brush / dotted line output with opaque background color or not with background 2 SetBkMode GetBkMode
How bitmaps are stretched on blt operations ? 3 SetStretchBltMode GetStretchBltMode
How pen / brush and surface are combined (boolean operations) Copy pen 2 SetROP2 GetROP2
Something else
Path (Prepared lines) empty path 4 BeginPath, EndPath … -
Context stack empty 2 SaveDC RestoreDC

To be continued …

Brush object[edit]

Windows uses brushes to paint colors and fill areas with predefined patterns. Brushes have a minimum size of 8X8 pixels and like pens, have three basic characteristic: size, pattern and color. With their 8X8 pixel minimum size,brushes are said to have a pattern, not a style as pens do. The pattern may be a solid color, hatched, diagonal or any other user definable combination, even a bitmap pattern.

case WM_PAINT:
    /* This will paint a red rectangle */
    HDC holdBrush; 
    HDC hdc = BeginPaint(hwnd, &ps);
    HBRUSH hBrush = CreateSolidBrush(RGB(255,0,0));

    holdBrush = SelectObject(hdc, hBrush);
    Rectangle(hdc, 10, 10, 100, 100); 
    /* Memory management has been omitted for brevity */
    EndPaint(hwnd, &ps); 

What's behind the brush object?

On creation, see LOGBRUSH structure Modification
Color (RGB color, can be dithered at realization) SetDCBrushColor
Style (solid, hatched, or bitmap) -
Bitmap (for bitmap style) -
Hidden fields on realization
Referencing device context (to track whether realization is still valid) UnrealizeObject
Device-dependent, possibly dithered bitmap, typically 8x8 size -

Note that a bitmap pattern brush behaves differently from a hatched brush, even when the bitmap looks like the hatch. Hatched brushes are transparent, whereas bitmap brushes are opaque. If a black-and-white bitmap is used, black is replaced by the Device Context's text color, and white is replaced by the background color. (This is exactly the BitBlt() behaviour.) SetBkMode() won't work. However, DC's ROP2 applies.

Pen object[edit]

Pens are used to create borders around shapes you have drawn.

Visible fields, see LOGPEN structure Windows version Modification
Width, in horizontal(!) logical units, 0 = 1 pixel 2 -
Style (solid or somehow dotted) 2 -
User dotting style (for user style selected) 4 -
Color 2 SetDCPenColor
Brush (Content: See above) 4 -
Geometric / Cosmetic flag 4 -
Hint how to draw line ends 4 -
Hint how to draw line joins 4 -
Hidden fields
Referencing device context (to track validity of other hidden fields) 2 UnrealizeObject?
Width in device pixels 2 -
Palette index of given color 2 -
Device-dependent bitmap for filling wide lines 2 -

Lines which result in widths larger than 1 device pixel (not logical units) are drawn as polygons with winding rule. Line colors are never dithered, except ExtCreatePen with a solid brush is used.

Font object[edit]

Fonts are for displaying text and symbols in various styles and sizes. Internal large differences exist for font management between Windows 2 (very basic), 3.1 (introducing TrueType), and 4+ (Unicode; world-transform rotation and mirroring; escapement can differ from rotation).

See LOGFONT structure for visible fields.

Hidden fields include

  • Referencing device context
  • Device-dependent bitmap font representation

Therefore, selecting a font into a Device Context (SelectObject) can be time-consuming, especially for large Asian fonts and large font sizes, to “paint” all the glyphs out of the TrueType template into the bitmap. Furthermore, as for all GDI objects, it's not a good idea to select one object from one to another context, because invalidating the hidden files can be a time-consuming process. Note that any GDI object cannot be selected into more that one DC.

Basic Drawing[edit]

In Windows, drawing is typically handled by the WM_PAINT message. The following is an example of how to draw a red square:

case WM_PAINT:
        PAINTSTRUCT ps;
        BeginPaint(hwnd, &ps);
        // RECT defines the upper-left and lower-right corners of a rectangle
        RECT rectangle = {50, 50, 250, 250};
        HBRUSH hbr = CreateSolidBrush(RGB(125, 0, 0));
        FillRect(ps.hdc, &rectangle, hbr);
        EndPaint(hwnd, &ps);

Firstly, we create the PAINTSTRUCT variable ps. This is a data structure containing information about the painting operation. The next line calls BeginPaint. This initializes ps, then fills it with relevant information. For this example, we only need the hdc member of ps. This is a handle to our window's Device Context. Next, we create a rectangle. This holds the upper-left and lower-right coordinates we're going to paint this rectangle at. The coordinates are relative to the upper-left corner of the window's client area. We also have to create a brush, otherwise Windows won't know what color to paint the rectangle. Finally, we call FillRect, and pass the parameters ps.hdc, a pointer to rectangle, and hbr, our brush. This paints the rectangle directly to our window's device context, and from there it is painted on the screen. After every painting operation, it is necessary to clean up any GDI objects we use, in this case hbr and ps.

Advanced hint[edit]

Because Windows should respond to WM_PAINT and WM_PRINTCLIENT, a more general rule for writing a WM_PAINT handler is this:

case WM_PRINTCLIENT: OnPaint((HDC)wParam, NULL); break;
case WM_PAINT: {
  BeginPaint(hwnd, &ps);
  OnPaint(ps.hdc, &ps.rcPaint);     // It's a good idea to manage the update area. Other PAINTSTRUCT fields are of less usefulness.
  EndPaint(hwnd, &ps);
// Somewhere else
void OnPaint(HDC dc, RECT* rcUpdate) {


Next Chapter[edit]