MFC Graphics and Drawing
This section provides comprehensive guidance on leveraging the Microsoft Foundation Classes (MFC) for graphics and drawing operations within your Windows applications. MFC offers a powerful abstraction layer over the Windows GDI (Graphics Device Interface), simplifying the process of creating visual elements, manipulating images, and rendering complex graphics.
Understanding the Device Context (DC)
The cornerstone of graphics programming in Windows and MFC is the Device Context (DC). A DC is a structure that contains information about the drawing attributes of a device, such as the screen or a printer. In MFC, the CDC class represents a device context.
Key aspects of the DC include:
- Mapping Modes: Define how logical units (like pixels) are mapped to device units (like inches).
- Pens, Brushes, and Fonts: Objects used to draw lines, fill areas, and render text.
- Color Palettes: Manage the colors available for display.
- Drawing Functions: A rich set of functions for drawing primitives, text, bitmaps, and more.
Working with CDC Objects
You'll typically obtain a CDC object within the OnDraw method of your view class or when handling a WM_PAINT message. For temporary drawing operations, you can create CPaintDC or CClientDC objects.
void CMyView::OnDraw(CDC* pDC)
{
// Get the client area rectangle
CRect rectClient;
GetClientRect(&rectClient);
// Set a pen for drawing lines
CPen pen(PS_SOLID, 2, RGB(255, 0, 0)); // 2-pixel wide solid red pen
CPen* pOldPen = pDC->SelectObject(&pen);
// Draw a line from (10, 10) to (100, 100)
pDC->MoveTo(10, 10);
pDC->LineTo(100, 100);
// Set a brush for filling shapes
CBrush brush(RGB(0, 255, 0)); // Green brush
CBrush* pOldBrush = pDC->SelectObject(&brush);
// Draw a rectangle
pDC->Rectangle(150, 50, 250, 150);
// Restore the original pen and brush
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}
Drawing Primitives
MFC provides member functions in the CDC class for drawing basic shapes:
MoveTo(),LineTo(): For drawing lines.Rectangle(),RoundRect(): For drawing rectangles.Ellipse(),Circle(): For drawing ellipses and circles.Polygon(),Polyline(): For drawing arbitrary polygons and polylines.Arc(): For drawing arcs.
Text Rendering
Displaying text is a common requirement. MFC's CDC class offers functions to draw text with specified fonts, colors, and alignment.
SetTextColor(): Sets the color for text.SetBkColor(): Sets the background color for text.SetTextAlign(): Controls text alignment relative to a given point.TextOut(): Draws a string of characters.DrawText(): Draws formatted text, allowing for word wrapping and alignment within a rectangle.
Working with Fonts
Use the CFont class to create and manage font objects. You can specify font characteristics like face name, height, width, weight, and italic style.
void CMyView::OnDraw(CDC* pDC)
{
// Create a new font
CFont font;
font.CreateFont(
24, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_BOLD, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS); // nPitchAndFamily
CFont* pOldFont = pDC->SelectObject(&font);
pDC->TextOut(50, 200, _T("Hello, MFC Graphics!"));
pDC->SelectObject(pOldFont); // Restore original font
}
Bitmaps and Images
MFC simplifies the process of loading, displaying, and manipulating bitmap images. The CBitmap class is used to represent bitmap data.
LoadBitmap(): Loads a bitmap from resources.BitBlt(): Performs a block transfer of a bitmap.StretchBlt(): Copies a bitmap, stretching or compressing it to fit a destination rectangle.
For more advanced image manipulation, consider using the GDI+ API available through MFC, which offers object-oriented graphics capabilities.
GDI Objects and Best Practices
When working with GDI objects like pens, brushes, and fonts, it's crucial to manage their lifecycle correctly. Always select your custom GDI objects into the device context and then select the original object back out before it's destroyed. Failure to do so can lead to resource leaks.
// Correct way to use a GDI object
CPen myPen;
myPen.CreatePen(PS_SOLID, 1, RGB(0,0,255));
CPen* pOldPen = pDC->SelectObject(&myPen);
// ... draw with myPen ...
pDC->SelectObject(pOldPen); // Always restore
// myPen is automatically destroyed when it goes out of scope
Never delete a GDI object that has been selected into a CDC. Always restore the previous object first.