visual-c++mfcgdicbitmap

Beginner In MFC C++, why does the device context need to create an old Font/Bitmap/etc pointer and then selectObject() it at the end?


Case in point:

void CMainWindow::OnPaint ()
{
    CRect rect;
    GetClientRect (&rect);

    CPaintDC dc (this);
    dc.SetViewportOrg (rect.Width () / 2, rect.Height () / 2);
    dc.SetBkMode (TRANSPARENT);

    for (int i=0; i<3600; i+=150) {
        LOGFONT lf;
        ::ZeroMemory (&lf, sizeof (lf));
        lf.lfHeight = 160;
        lf.lfWeight = FW_BOLD;
        lf.lfEscapement = i;
        lf.lfOrientation = i;
        ::lstrcpy (lf.lfFaceName, _T ("Arial"));

        CFont font;
        font.CreatePointFontIndirect (&lf);

        CFont* pOldFont = dc.SelectObject (&font);
        dc.TextOut (0, 0, CString (_T ("          Hello, MFC")));

        //WHY THIS LINE?
        dc.SelectObject (pOldFont);
    }
}

The code prints " Hello, MFC" in a circle around the origin (which is moved to the center of the window).

Output

Why is that CFont pointer created and then the dc selects it as the font? Is that just good programming practice or does this app actually need it?

I've seen similar code on the web doing this with Bitmaps and other device context objects. What's the purpose?

When I remove that last line of the code, nothing changes. Thanks in advance for the help.


Solution

  • Device Context:

    A device context is a structure that defines a set of graphic objects and their associated attributes, as well as the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other operations, and a path for painting and drawing operations.

    At any time, there is exactly one graphic object selected into a device context. Since the system stores a set of default objects into a device context when it is created, an application must retain that state, when the device context is handed back to the system for cleanup. That is what

    dc.SelectObject (pOldFont);
    

    is responsible for.

    This requirement is documented under SelectObject:

    This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object.


    Note: This is not related to MFC, but rather the Windows GDI. MFC merely implements an automatic resource management wrapper. State management still requires explicit code.