PRB: Clipping Doesn't Work Correctly in Print Preview

This article was previously published under Q128334
This article has been archived. It is offered "as is" and will no longer be updated.
Symptoms
Using SelectClipRgn works correctly when viewing on-screen results or whenprinting but causes problems in print preview mode. Problems include notdisplaying anything or not clipping anything. This happens even though thereturn value from SelectClipRgn appears to be correct; that is, it does notreturn NULLREGION even though all output appears to be getting clipped.
Cause
The CDC class encapsulates two HDC handles. One is called m_hAttribDC andthe other is m_hDC. See the CDC documentation for more information on thisaspect of the CDC class.

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

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

The SelectClipRgn function takes a clipping region that was created usingdevice pixels for its area. It then attempts to select it as the clippingrectangle for both the m_hDC and the m_hAttribDC. The device coordinatesspecified by your application will correspond to printer coordinates andnot screen coordinates. Therefore, they won't match up properly when yourclipping region is selected into the print preview DC.
Resolution
During print preview mode MFC actually uses a CDC-derived class to handlesome of the special print preview operations such as mapping your printercoordinates to screen coordinates. This class is called CPreviewDC and isdeclared in <afxpriv.h>. There is no way for MFC to provide specialhandling for a clipping region because the RGN object is created withoutusing CPreviewDC, and the CPreviewDC class is simply used for selecting theRGN object into the DC.

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

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

An example of how to do the coordinate conversion before creating yourclipping region is included in the "Sample Code" section below. Note thatthe code in this example exists in the view's OnDraw function. It couldalso be placed in the OnPrint function but it would not work correctly ifplaced in OnPrepareDC. This is because the viewport setup for Print Previewmode takes place after OnPrepareDC and before OnPrint (or OnDraw if you donot 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.
1.00 1.50 2.00 2.10 2.50 2.51 2.52 3.00 3.10 4.00
Properties

Article ID: 128334 - Last Review: 11/01/2013 21:22:00 - Revision: 4.0

  • Microsoft Foundation Class Library 4.2
  • kbnosurvey kbarchive kbcode kbprb kbuidesign KB128334
Feedback