PRB: Clipping Doesn't Work Correctly in Print Preview

ID: Q128334


The information in this article applies to:
  • The Microsoft Foundation Classes (MFC), included with:
    • Microsoft Visual C++ for Windows, 16-bit edition, versions 1.0, 1.5, 1.51, 1.52
    • Microsoft Visual C++, 32-bit Editions, versions 1.0, 2.0, 2.1, 4.0


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.

Additional query words: 1.00 1.50 2.00 2.10 2.50 2.51 2.52 2.10 3.00 3.10 4.00

Keywords : kbcode kbMFC KbUIDesign kbVC
Version : 1.00 1.50 1.51 1.52 | 1.00 2.00
Platform : NT WINDOWS
Issue type :


Last Reviewed: July 28, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.