GDI Objects

A Windows GDI object type is represented by an MFC library class. CGdiObject is the abstract base class for the GDI object classes. A Windows GDI object is represented by a C++ object of a class derived from CGdiObject. Here's a list of the GDI derived classes:

  • CBitmap—A bitmap is an array of bits in which one or more bits correspond to each display pixel. You can use bitmaps to represent images, and you can use them to create brushes.

  • CBrush—A brush defines a bitmapped pattern of pixels that is used to fill areas with color.

  • CFont—A font is a complete collection of characters of a particular typeface and a particular size. Fonts are generally stored on disk as resources, and some are device-specific.

  • CPalette—A palette is a color mapping interface that allows an application to take full advantage of the color capability of an output device without interfering with other applications.

  • CPen—A pen is a tool for drawing lines and shape borders. You can specify a pen's color and thickness and whether it draws solid, dotted, or dashed lines.

  • CRgn—A region is an area whose shape is a polygon, an ellipse, or a combination of polygons and ellipses. You can use regions for filling, clipping, and mouse hit-testing.

Constructing and Destroying GDI Objects

You never construct an object of class CGdiObject; instead, you construct objects of the derived classes. Constructors for some GDI derived classes, such as CPen and CBrush, allow you to specify enough information to create the object in one step. Others, such as CFont and CRgn, require a second creation step. For these classes, you construct the C++ object with the default constructor and then you call a create function such as the CreateFont or CreatePolygonRgn function.

The CGdiObject class has a virtual destructor. The derived class destructors delete the Windows GDI objects that are attached to the C++ objects. If you construct an object of a class derived from CGdiObject, you must delete it prior to exiting the program. To delete a GDI object, you must first separate it from the device context. You'll see an example of this in the next section.

Failure to delete a GDI object was a serious offense with Win16. GDI memory was not released until the user restarted Windows. With Win32, however, the GDI memory is owned by the process and is released when your program terminates. Still, an unreleased GDI bitmap object can waste a significant amount of memory.

Tracking GDI Objects

OK, so you know that you have to delete your GDI objects and that they must first be disconnected from their device contexts. How do you disconnect them? A member of the CDC::SelectObject family of functions does the work of selecting a GDI object into the device context, and in the process it returns a pointer to the previously selected object (which gets deselected in the process). Trouble is, you can't deselect the old object without selecting a new object. One easy way to track the objects is to "save" the original GDI object when you select your own GDI object and "restore" the original object when you're finished. Then you'll be ready to delete your own GDI object. Here's an example:

 void CMyView::OnDraw(CDC* pDC) {     CPen newPen(PS_DASHDOTDOT, 2, (COLORREF) 0);  // black pen,                                                   //  2 pixels wide     CPen* pOldPen = pDC->SelectObject(&newPen);     pDC->MoveTo(10, 10);     pDC->Lineto(110, 10);     pDC->SelectObject(pOldPen);                   // newPen is deselected } // newPen automatically destroyed on exit 

When a device context object is destroyed, all its GDI objects are deselected. Thus, if you know that a device context will be destroyed before its selected GDI objects are destroyed, you don't have to deselect the objects. If, for example, you declare a pen as a view class data member (and you initialize it when you initialize the view), you don't have to deselect the pen inside OnDraw because the device context, controlled by the view base class's OnPaint handler, will be destroyed first.

Stock GDI Objects

Windows contains a number of stock GDI objects that you can use. Because these objects are part of Windows, you don't have to worry about deleting them. (Windows ignores requests to delete stock objects.) The MFC library function CDC::SelectStockObject selects a stock object into the device context and returns a pointer to the previously selected object, which it deselects. Stock objects are handy when you want to deselect your own nonstock GDI object prior to its destruction. You can use a stock object as an alternative to the "old" object you used in the previous example, as shown here:

void CMyView::OnDraw(CDC* pDC) {     CPen newPen(PS_DASHDOTDOT, 2, (COLORREF) 0);  // black pen,                                                   //  2 pixels wide     pDC->SelectObject(&newPen);     pDC->MoveTo(10, 10);     pDC->Lineto(110, 10);     pDC->SelectStockObject(BLACK_PEN);            // newPen is deselected } // newPen destroyed on exit 

The Microsoft Foundation Class Reference lists, under CDC::SelectStockObject, the stock objects available for pens, brushes, fonts, and palettes.

The Lifetime of a GDI Selection

For the display device context, you get a "fresh" device context at the beginning of each message handler function. No GDI selections (or mapping modes or other device context settings) persist after your function exits. You must, therefore, set up your device context from scratch each time. The CView class virtual member function OnPrepareDC is useful for setting the mapping mode, but you must manage your own GDI objects.

For other device contexts, such as those for printers and memory buffers, your assignments can last longer. For these long-life device contexts, things get a little more complicated. The complexity results from the temporary nature of GDI C++ object pointers returned by the SelectObject function. (The temporary "object" will be destroyed by the application framework during the idle loop processing of the application, sometime after the handler function returns the call. See MFC Technical Note #3 in the online documentation.) You can't simply store the pointer in a class data member; instead, you must convert it to a Windows handle (the only permanent GDI identifier) with the GetSafeHdc member function. Here's an example:

// m_pPrintFont points to a CFont object created in CMyView's constructor // m_hOldFont is a CMyView data member of type HFONT, initialized to 0 void CMyView::SwitchToCourier(CDC* pDC) {     m_pPrintFont->CreateFont(30, 10, 0, 0, 400, FALSE, FALSE,                              0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,                              CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,                              DEFAULT_PITCH | FF_MODERN,                               "Courier New"); // TrueType     CFont* pOldFont = pDC->SelectObject(m_pPrintFont);     // m_hOldFont is the CGdiObject public data member that stores     //  the handle     m_hOldFont = (HFONT) pOldFont->GetSafeHandle(); } void CMyView:SwitchToOriginalFont(CDC* pDC) {     // FromHandle is a static member function that returns an     //  object pointer     if (m_hOldFont) {         pDC->SelectObject(CFont::FromHandle(m_hOldFont));     } } // m_pPrintFont is deleted in the CMyView destructor 

Be careful when you delete an object whose pointer is returned by SelectObject. If you've allocated the object yourself, you can delete it. If the pointer is temporary, as it will be for the object initially selected into the device context, you won't be able to delete the C++ object.



Programming Microsoft Visual C++
Programming Microsoft Visual C++
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 332

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net