PRB: Clipping Doesn't Work Correctly in Print Preview

Article translations Article translations
Article ID: 128334 - View products that this article applies to.
This article was previously published under Q128334
This article has been archived. It is offered "as is" and will no longer be updated.
Expand all | Collapse all

On This Page

Symptoms

Using SelectClipRgn works correctly when viewing on-screen results or when printing but causes problems in print preview mode. Problems include not displaying anything or not clipping anything. This happens even though the return value from SelectClipRgn appears to be correct; that is, it does not return NULLREGION even though all output appears to be getting clipped.

Cause

The CDC class encapsulates two HDC handles. One is called m_hAttribDC and the other is m_hDC. See the CDC documentation for more information on this aspect of the CDC class.

The m_hAttribDC member is the same as the m_hDC member when you are printing or just drawing on the screen. However, in Print Preview mode, the m_hDC member points to the screen DC for your printed output, and the m_hAttribDC member references a printer DC for getting printer attributes during the print preview operation.

The print preview output view is mapped using SetViewportExt and SetWindowExt, so that you can call the CDC member functions as though you were putting your output to the printer and your output will be properly scaled to the print preview window. This works fine for any function that works with logical coordinates or for which the print preview output can be intercepted and modified.

The SelectClipRgn function takes a clipping region that was created using device pixels for its area. It then attempts to select it as the clipping rectangle for both the m_hDC and the m_hAttribDC. The device coordinates specified by your application will correspond to printer coordinates and not screen coordinates. Therefore, they won't match up properly when your clipping region is selected into the print preview DC.

Resolution

During print preview mode MFC actually uses a CDC-derived class to handle some of the special print preview operations such as mapping your printer coordinates to screen coordinates. This class is called CPreviewDC and is declared in <afxpriv.h>. There is no way for MFC to provide special handling for a clipping region because the RGN object is created without using CPreviewDC, and the CPreviewDC class is simply used for selecting the RGN object into the DC.

So you must convert your RGN coordinates before creating the RGN. The CPreviewDC class has a function called PrinterDPtoScreenDP that you can use to help in this conversion. The function converts a printer device coordinate to a screen coordinate. All you need to do is convert all coordinates before creating your RGN object.

You will only want to do this when you are in Print Preview mode. As mentioned above, MFC uses the CPreviewDC class when you are in print preview and you can detect whether this class is being used by using the IsKindOf function.

An example of how to do the coordinate conversion before creating your clipping region is included in the "Sample Code" section below. Note that the code in this example exists in the view's OnDraw function. It could also be placed in the OnPrint function but it would not work correctly if placed in OnPrepareDC. This is because the viewport setup for Print Preview mode takes place after OnPrepareDC and before OnPrint (or OnDraw if you do not have an overriden OnPrint) is called.

Sample Code

// Note that afxpriv.h must be included to get the declaration
// of the CPreviewDC class. The following line should be included
// at the very top of your view's .CPP file

#include <afxpriv.h>

// ...

void CMyView::OnDraw(CDC *pDC)
    {
    CRgn rgn;
    CRect rectClip;

    // Function to compute the clipping rectangle regardless of
    // whether we are in print preview mode. This would be the
    // function in your code which computes this rectangle and
    // stores it in rectClip

    ComputeClippingRectangle(pDC,&rectClip);

    // Now if we are in print preview mode then the clipping
    // rectangle needs to be adjusted before creating the
    // clipping region
    if (pDC->IsKindOf(RUNTIME_CLASS(CPreviewDC)))
        {
        CPreviewDC *pPrevDC = (CPreviewDC *)pDC;

        pPrevDC->PrinterDPtoScreenDP(&rectClip.TopLeft());
        pPrevDC->PrinterDPtoScreenDP(&rectClip.BottomRight());

        // Now offset the result by the viewport origin of
        // the print preview window...

        CPoint ptOrg;
         ::GetViewportOrgEx(pDC->m_hDC,&ptOrg);
        rectClip += ptOrg;
        }

    // The following two function calls are the ones that
    // select the clipping region into the DC. These would be
    // whatever code you already have to create/select the
    // clipping region

    rgn.CreateRectRgn(rectClip.left,rectClip.top,
        rectClip.right,rectClip.bottom);
    pDC->SelectClipRgn(&rgn);

    // Other OnDraw code goes here
    }
				

Status

This behavior is by design.

Properties

Article ID: 128334 - Last Review: November 1, 2013 - Revision: 4.0
Applies to
  • Microsoft Foundation Class Library 4.2, when used with:
    • Microsoft Visual C++ 1.0 Professional Edition
    • Microsoft Visual C++ 1.52 Professional Edition
    • Microsoft Visual C++ 2.1
    • Microsoft Visual C++ 4.0 Standard Edition
Keywords: 
kbnosurvey kbarchive kbcode kbprb kbuidesign KB128334

Give Feedback

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com