Drawing in Windows

Windows application programs run in the desktop graphical environment and there are basic requirements for displaying pictures, drawings and graphics etc. Basic requirements are to draw some figures or to show images to the screen in flash screen, startup dialogs, about box.

There are graphics-intensive applications like a game, graphics editor, or animation editor, where drawing on the window comes as a fundamental requirement. A programmer must obtain the device context of the window to start the drawing steps. All the drawing and GDI operations are done on the device context handle.

Device Context

A device context (DC) is a data structure in Windows graphical programming practices that contains information of the drawing attributes of an output device such as a graphics display or a printer. Know more: Device Context

A device context is a structure that defines a set of graphic objects and their associated attributes, and the graphic modes that affect output. The graphic objects pen, brush, bitmap, palette, region for clipping and other operations, and a path for painting and drawing operations.

GDI Objects

Drawing on the device context is done with the help of Graphics Device Interface (GDI) objects. A set of GDI objects is defined in the Windows graphics subsystem which acts as the utility tools for drawing on the device context.

  • Pen Object - A pen is a GDI tool used to draw lines and outer lines of different graphical shapes. Know more: Pen Object
  • Brush Object - A brush tool is used to fill the inner area of any closed shapes. Know more: Brush Object
  • Font Object - Fonts are small bitmaps of text characters. A font object defines how the text strings will appear on the device. Know more: Font Object
  • Bitmap Object - A bitmap pictures contains an image or photo. A picture can be displayed on the device using a bitmap. Know more: Bitmap Object
  • Palette Object - A Palette object is a GDI tool to hold a collection of colors for the drawing on the device. Know more: Palette Object
  • Region Object - Region object is a object that tells the area or region on the drawing area on the device.

Drawing on WM_PAINT event

Programmer creates a window or creates a dialog. A series of events are passed to the window procedure of that window object. WM_CREATE is sent on the creation of the window. Then programmer should update the window should call UpdateWindow. A call to UpdateWindow sends a WM_PAINT event and We can draw something on the window on this event handler. WM_PAINT event is sent by the Win32 GUI framework at the time of drawing of the window i.e. after the call of UpdateWindow() or when RedrawWindow is called when a part of the window requires an update. ShowWindow() API call with SW_SHOW/SW_NORMAL parameter displays the window in the desktop.

Programmer should obtain the device context using BeginPaint() API call and then drawing can be done using various GDI calls. At the end of the GDI calls programmers should call EndPaint(). More details : BeginPaint & EndPaint

Window message PAINT

Parameters: wParam is the hdc i.e. the handle to the device context to draw in. The value of NULL handle means use the default device context. This parameter is used by some common controls to enable drawing in a device context other than the default device context. Other windows can safely ignore this parameter.

message = WM_PAINT 
hdc = (HDC) wParam; /* the device context to draw in*/

BeginPaint & EndPaint

BeginPaint()- EndPaint() are functions should be used in pairs. Programmer should start the drawing session with BeginPaint() and EndPaint() should be called at the end of all steps before exittting the event routine. BeginPaint()- EndPaint() are used in WP_PAINT message handling and . GetDC() - ReleaseDC() pair functions are used to draw in any other context than WP_PAINT. More details : GetDC & GetWindowDC

BeginPaint

The BeginPaint function starts the specified window for painting and fills a PAINTSTRUCT structure with information about the painting. PAINTSTRUCT.hdc holds the handle to the device context of the window. All further GDI calls should use this device context for drawings.

HDC BeginPaint(
  HWND hwnd,  /* handle to window */
  LPPAINTSTRUCT lpPaint /* pointer to structure for paint information */
);

EndPaint

The EndPaint function should be called to mark the end of the painting in the specified window. This function should be called after the call of BeginPaint function and with the same parameters but only after the painting steps are complete.

BOOL EndPaint(
  HWND hWnd,  /* handle to window */
  CONST PAINTSTRUCT *lpPaint /* pointer to structure for paint data */
);

Source Code

We are drawing a string saying hello in the WM_PAINT event. The text is displayed at (0,0) location in the window i.e. at the left top location. We have used SetTextColor() GDI call to set the attribute of the text color as RED.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd,
                         UINT message, 
                         WPARAM wParam,
                         LPARAM lParam);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  WNDCLASS wc;
  MSG msg;
  HWND hWnd;
  ZeroMemory(&wc, sizeof(WNDCLASS));

  wc.style           = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc     = (WNDPROC)WndProc;
  wc.hInstance       = hInstance;
  wc.hCursor         = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground   = (HBRUSH)(COLOR_BACKGROUND-1);
  wc.lpszClassName   = (LPCTSTR)"wm_paintWin32Class";


  RegisterClass(&wc);

   hWnd = CreateWindow("wm_paintWin32Class", "WM_PAINT event demo", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while (GetMessage(&msg, NULL, 0, 0)) 
  {
    DispatchMessage(&msg);
  }
  return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;

  switch (message) 
  {
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      SetTextColor(hdc, RGB(255,0,0));
      TextOut(hdc, 0, 0, "Hello, from WM_PAINT event!", 27); 
      EndPaint(hWnd, &ps); 
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
    default :
      return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

WM_PAINT

About our authors: Team EQA

Further readings

Where is WinMain() function in MFC application ?

MFC hides WinMain in its framework and includes source file on WinMain(). This explains how framework calls global CWinApp::Initinstance() from entry WinMain.

What is the utility of CWinApp class?

This is constructed during global C++ objects are constructed and is already available when Windows calls the WinMain function, which is supplied by the ...

Basic steps in Win32 GUI Application with source code.

Define a custom Window class structure, Register the class name, CreateWindow, Show windows and write message get and dispatch loop statements. Define the Window CallBack procedure and write the handlers.

What is a Window CallBack procedure and what is its utility?

DispatchMessage() is a API which indirectly triggers the Window CallBack procedure. Message structure members from this function are passed to the CallBack procedure. CallBack procedure should implement event handlers depending on the need of the application.

What are LPARAM and WPARAM in window proc function?

LPARAM and WPARAM are the two parameters in Window CallBack procedure. They signifies parameters of various events. They are used in handing individual events.

What are the basic steps of a typical MFC based application?

We need to write WinMain and need to follow all these in a Win32 application. However we need not to write much if we are writing an application with MFC ...

#