Your browser doesn't support JavaScript Working with Graphics – Windows Programming

Working with Graphics


In MFC, the CDC class provides a C++ wrapper around the Windows device context (DC) and the associated Graphics Device Interface (GDI) functions used for drawing on display devices. The Windows graphics system uses graphical objects such as pens, brushes, fonts, bitmaps, and palettes to control the appearance of graphical output.

A pen defines the colour, width and line style used to draw lines, curves and the outlines of shapes. A brush determines how the interior of closed shapes, such as rectangles and circles, is filled. Fonts specify the appearance of text, while bitmaps and palettes are used for displaying images and managing colours.

When Windows creates a device context, it automatically contains a default set of graphical objects known as stock objects. These include a limited selection of pens, brushes, fonts and palettes that applications can use without creating their own graphics objects.

If an application requires drawing attributes that differ from the default settings, it must first create the required graphical object and then select it into the device context using one of the SelectObject() functions. Once selected, the new object remains active until another object of the same type is selected into the device context. Changing the selected pen, brush or font affects only subsequent drawing operations; graphics that have already been drawn on the display remain unchanged.

For efficient resource management, any application-created graphical object should be deselected from the device context before it is destroyed, and the original object restored. This ensures that Windows resources are released correctly and helps prevent resource leaks.

Creating Custom Pens

The default pen draws solid black lines that are 1 pixel wide. The CDC member function CreatePen() deals with creating custom pens. The prototype of this function is

BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor );

Were.
nPenStyle -can be any one of the following values: PS_SOLID, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL, PS_INSIDEFRAME,
nWidth – Specifies the width of the pen
crColor – Contains an RGB colour for the pen.

If the function succeeds, the return value is a handle that identifies a logical pen. If the function fails, the return value is NULL.

For further reading
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdicreatepen

Create Custom Brushes

Brushes are used to fill in any closed objects. They have colour, style, and can be bitmaps. The CBrush class encapsulates GDI brushes and supplies various member functions to deal with the creation of custom brushes. The prototype for the CreateSolidBrush() function is:

BOOL CreateSolidBrush(COLORREF crColor);

where
crColor is a COLORREF structure that specifies the RGB colour of the brush. Return Nonzero if successful; otherwise 0.

For further reading on brush creation
https://docs.microsoft.com/en-us/cpp/mfc/reference/cbrush-class?view=vs-2019

Selecting Objects

Before any graphics object can be used it must be ‘selected’ into the current device context (DC) using the CDC member function SelectObject(). The new object will then replace the previous graphic object of the same type. The prototype of the SelectObject function for both a Pen() and a Brush() is:

CPen* SelectObject(CPen* pPen); CBrush* SelectObject(CBrush* pBrush);

Where
pPen – A pointer to a CPen object to be selected.
pBrush – A pointer to a CBrush object to be selected.

SelectObject will return a pointer to the previous graphics objects which may be useful should the application need to use the previous selection

For further reading
https://docs.microsoft.com/en-us/cpp/mfc/reference/cdc-class?view=vs-2019#selectobject

Using Stock Objects

The CDC member function SelectStockObject() retrieves a handle to a stock object. The prototype of this function is:

virtual CGdiObject* SelectStockObject(int nIndex);

Where the parameter nIndex can be one of the following values: BLACK_BRUSH, DKGRAY_BRUSH ,DC_BRUSH ,GRAY_BRUSH ,HOLLOW_BRUSH ,LTGRAY_BRUSH ,NULL_BRUSH ,WHITE_BRUSH ,BLACK_PEN ,DC_PEN ,NULL_PEN ,WHITE_PEN, ANSI_FIXED_FONT ,ANSI_VAR_FONT ,DEVICE_DEFAULT_FONT ,DEFAULT_GUI_FONT ,OEM_FIXED_FONT ,SYSTEM_FONT ,SYSTEM_FIXED_FONT , DEFAULT_PALETTE

If the function succeeds, the return value is a handle to the requested logical object. If the function fails, the return value is NULL

To select a stock object such as BLACK_PEN into the current device context

SelectObject(GetStockObject(BLACK_PEN));

Since stock objects are pre-created system resources there is no need to delete the object handle once they are no longer required.

For further reading on stock objects
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getstockobject

SaveDC and RestoreDC.

SaveDC() and RestoreDC() allow an application to save and restore the complete state of a device context. Each time an application requests a device context, its attributes are reset to the Windows defaults, meaning any custom pens, brushes, fonts, colours, clipping regions or mapping modes previously selected are lost.

To avoid repeatedly reinitialising the device context, the current state can be saved using SaveDC() before making changes and later restored using RestoreDC(). This is particularly useful when temporarily changing drawing attributes, as it allows the original settings to be reinstated with a single function call.

The prototypes of these member functions are:

int SaveDC();

BOOL RestoreDC(int nSavedDC);

Where:

  • SaveDC() saves the current state of the device context and returns an integer identifying the saved state.
  • RestoreDC(int nSavedDC) restores the device context to the state identified by nSavedDC.

Deleting GDI Objects

Custom pens, brushes and other objects created from GDI classes consume system resources. It is therefore important that they are deleted when they are no longer required.

If a GDI object is created on the stack, it is automatically destroyed when it goes out of scope, so no explicit deletion is necessary. However, if a GDI object is created on the heap using new, it must be explicitly deleted by calling the object’s DeleteObject() member function before deleting the object itself.

Objects created using CreateStockObject() represent Windows stock objects and must not be deleted, as they are owned and managed by the operating system.

Failure to delete dynamically created GDI objects results in a resource leak (often referred to as a memory or GDI leak), gradually reducing the number of GDI resources available to the application. Excessive leaks can eventually prevent the application from creating new pens, brushes, fonts or other graphical objects, leading to drawing errors or application failure.

Dealing with Colour Values

The Windows graphics system uses the RGB (Red, Green, Blue) colour model to specify colours. Every colour is defined by three components: red, green, and blue, each with an intensity value ranging from 0 to 255, where 0 represents no intensity and 255 represents maximum intensity. By combining different intensities of these three primary colours, over 16 million different colours can be produced.

Windows stores colours using the COLORREF data type, which is a 32-bit value containing the RGB colour information. Rather than specifying the individual colour components separately, the Windows GDI provides macros for creating and extracting COLORREF values.

//converts rgb to colourref value COLORREF RGB(BYTE byRed, BYTE byGreen, BYTE byBlue); //converts colourref value to RGB equivalent int iRed= GetRValue(COLORREF rgb); int iGreen =GetGValue(COLORREF rgb); int iBlue =BYTE GetBValue(COLORREF rgb);

A full description of all the CDC member functions covering graphics output can be found at the following-
https://docs.microsoft.com/en-us/cpp/mfc/reference/cdc-class?view=vs-2019