Click here to Skip to main content
Click here to Skip to main content

MultiPage PrintPreview enhancements for MFC Doc/View applications

, 27 Apr 2002 CPOL
Rate this:
Please Sign up or sign in to vote.
How to improve the standard MFC print preview options to allow preview of from 1 to 9 pages at a time
<!-- Download Links --> <!-- Article image -->

Sample Image - 9pages.gif

<!-- Add the rest of your HTML here -->

Acknowledgements

First I would like to acknowledge some articals which I used as a reference when putting this project together.

Overview

The standard Print Preview mechanism supplied by MFC is a little understood phenomenon. There are few enhancements currently published for it, and none for showing more than 2 pages at a time in preview mode. I set out to solve this! It turned out to be reasonably easy to do, working from the examples supplied by Robin and Yasuhiko. In my solution I used small parts of both examples (Robins onwner drawn buttons, and Yasuhiko's extra zoom levels).

The enhancement are:

  • From 1 to 9 pages viewed at a time - selectable by a popup menu
  • The scrollbar will not allow blank pages to be scrolled into view
  • You can switch dynamically between portrait and landscape mode using the toolbar command
  • So how do you go about using this these enhancements?

    Adding the required resources

    To use this enhanced preview mode, you need to include the folowing resources into your project

    • The replacement toolbar resource
    • The popup menu resource
    • The button bitmaps
    • These should be copied and pasted into your project. You can do this from the VC IDE, or by manually editing the .rc file (not really recommended)

    Add the source files

    The enhanced preview uses the following source files:

    • MappedBitmapButton.cpp/h - Robin J. Leatherbarrow
    • MultiPagePreview.cpp/h - Myself with some code from Yasuhiko
    • An additional function in your CWinApp derived class - see later

    Replacing the standard Print Preview

    To replace the standard PrintPreview supplied by the MFC Doc/View architecture, you have to write a handler in your projects CView class to handle the ID_FILE_PRINT_PREVIEW command. You put the following code in that handler to supplant the MFC preview with the new one:

    // replace the default print preview with ours!
    
    // In derived classes, implement special window handling here
    // Be sure to Unhook Frame Window close if hooked.
        
    // must not create this on the frame.  Must outlive this function
    CPrintPreviewState* pState = new CPrintPreviewState;
        
    // DoPrintPreview's return value does not necessarily indicate that
    // Print preview succeeded or failed, but rather what actions are necessary
    // at this point.  If DoPrintPreview returns TRUE, it means that
    // OnEndPrintPreview will be (or has already been) called and the
    // pState structure will be/has been deleted.
    // If DoPrintPreview returns FALSE, it means that OnEndPrintPreview
    // WILL NOT be called and that cleanup, including deleting pState
    // must be done here.
        
    if (!DoPrintPreview(IDD_PREVIEW, this, RUNTIME_CLASS(CMultiPagePreviewView),
                        pState)) // note, put your class name in here
    {
        // In derived classes, reverse special window handling here for
        // Preview failure case
            
        TRACE0("Error: DoPrintPreview failed.\n");
        AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
        delete pState;      // preview failed to initialize, delete State now
        pState = NULL;
    }
    

    Update your CWinApp derived class

    The additonal functionality to switch dynamically between portrait and landscape mode in print preview requires support of an additional function in your CWinApp derived class. This is because the m_hDevMode object is a protected member and cannot be accessed directly by the preview class. The prototype of this function and the code for it is a follows:

    // prototype for CWinApp derived class
    void        SetPrintOrientation(int mode) ;
    
    void CYourApp::SetPrintOrientation(int mode)
    {
        switch (mode)
            {
            case DMORIENT_PORTRAIT :
                    {
                    // portrait mode
                    PRINTDLG pd;
                    pd.lStructSize = (DWORD)sizeof(PRINTDLG) ;
                    BOOL bRet = GetPrinterDeviceDefaults(&pd) ;
                    if (bRet)
                        {
                        // protect memory handle with ::GlobalLock and ::GlobalUnlock
                        DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(m_hDevMode) ;
                        // set orientation to portrait
                        pDevMode->dmOrientation = DMORIENT_PORTRAIT ;
                        ::GlobalUnlock(m_hDevMode) ;
                        }
                    }
                    break ;
            case DMORIENT_LANDSCAPE :
                    {
                    // landscape mode
                    PRINTDLG pd;
                    pd.lStructSize = (DWORD)sizeof(PRINTDLG) ;
                    BOOL bRet = GetPrinterDeviceDefaults(&pd) ;
                    if (bRet)
                        {
                        // protect memory handle with ::GlobalLock and ::GlobalUnlock
                        DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(m_hDevMode) ;
                        // set orientation to landscape
                        pDevMode->dmOrientation = DMORIENT_LANDSCAPE ;
                        ::GlobalUnlock(m_hDevMode) ;
                        }
                    }
                    break ;
            default :    ASSERT(FALSE) ;        // invalid parameter
            }
    }
    

    If your adding this to your application you will also have to mod the code so it uses your CWinApp derived class name and not that of the demo project. If you insert the code and compile. The errors generated will get you to the lines you will need to update.

    Once all of this is in, the preview mode should work automatically. You should now be able to preview upto a maximum of 9 pages simultaneously. This can be expanded for more by enhancing the options in the popup menu, and modifying the function CMultiPagePreviewView::OnPreviewPages() to handle the new layout. Just make sure that you increase the size of the m_pageInfoArray2 array in the .h file to avoid overwriting memory. So if you wanted to support a 4 * 4 preview, the array size needs to be increased from 9 to 16.

    Changes made

    • 24-4-2002 Release 1
    • 28-4-2002 Release 2 - Added portrait/landscale switching and update the scrollbar control code

    Future enhancements

    I would like to add in the future the following features:

    • Make the pages flicker free

    Or you could always add them yourselves.

    License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    Share

    About the Author

    Roger Allen
    Software Developer (Senior) Sirius Analytical Instruments
    United Kingdom United Kingdom
    A research and development programmer working for a pharmaceutical instrument company for the past 17 years.
     
    I am one of those lucky people who enjoys his work and spends more time than he should either doing work or reseaching new stuff. I can also be found on playing DDO on the Cannith server (Send a tell to "Maetrim" who is my current main)
     
    I am also a keep fit fanatic, doing cross country running and am seriously into [url]http://www.ryushinkan.co.uk/[/url] Karate at this time of my life, training from 4-6 times a week and recently achieved my 1st Dan after 6 years.

    Comments and Discussions

     
    QuestionWhat piece of code should I change to get rid of the spacing.. PinmemberMember 78714814-Mar-13 9:01 
    GeneralHello PinmemberMark Jefferson27-Apr-08 5:41 
    GeneralDon't need to modify you CWinApp class PinmemberWolfram Rösler21-Jan-07 22:59 
    Generalprinting PinmemberAlexDa2-Dec-05 0:25 
    GeneralCombine pages with portrait and landscape PinmemberStoil24-Sep-04 5:47 
    GeneralRe: Combine pages with portrait and landscape PinmemberStoil16-Oct-04 1:26 
    QuestionFont Bug ? Pinmembermroy_10016-Feb-04 6:44 
    GeneralFrom landscape to full setup Pinmemberasconaga3-Dec-03 4:08 
    GeneralProblem with hiding the view Pinmemberwolfbert17-Oct-03 3:27 
    Generalvery useful PinmemberMarco Walle25-Sep-03 6:45 
    GeneralJust a little improvement... PinmemberKickaha19-Sep-03 14:29 
    Generali want to send u my Projectzip PinmemberBalaji20001-Jun-03 21:57 
    GeneralAny body Know !..Help Me!.. PinmemberBalaji200029-May-03 3:07 
    is it Posible to Print richtext with in a given rectangle area
     
    don't worry with the size of file..
    is a simple thing i expliend in lot..
    Trying: Edit,RichEdit control printing,
    with in a rectangle as per they are drawn
    in scroll view..
     
    ----
    //***************************************************************************************
    // I want to draw the RichTextControl content in a specified rectangle on my printing page
    // (as i done with editbox control) using FormatRange function with the different
    // Font styles as in RichEditControl - HelpMe please!.
    // DrawRichText(CDC *pDC) -> could u solve the problem that i have in this function ?..
    //***************************************************************************************
    //The partial code
     
    //RTCtrlPrint1View.h
    public:
    CRTCtrlPrint1Doc* GetDocument();
    //My*************************************
    void RTCtrlCreate();
    void DrawRichText(CDC *pDC);
    void DrawEditText(CDC *pDC);
     
    CRichEditCtrl m_redit;
    CRect m_redRect;
     
    CEdit m_edit;
    CRect m_edRect;
    UINT r;
    CFont font;
    //***************************************
     
    //RTCtrlPrint1View.cpp
    //=======================
    void CRTCtrlPrint1View::OnInitialUpdate()
    {
    CScrollView::OnInitialUpdate();
     
    //edith box displaytext font
    font.CreateFont(14,0,0,0,FW_NORMAL,FALSE,FALSE,
    0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
    CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
    DEFAULT_PITCH|FF_MODERN,"Arial");
     
    r=14;
    m_edRect = CRect(50*r,-100*r,240*r,-700*r);
    m_redRect = CRect(250*r,-100*r,750*r,-700*r);
     
    CSize sizeTotal;
    sizeTotal.cx = 850*r;
    sizeTotal.cy = 1100*r;
    SetScrollSizes(MM_TWIPS, sizeTotal); //MM_TWIPS
     
    RTCtrlCreate();
    }
     
    void CRTCtrlPrint1View::OnDraw(CDC* pDC)
    {
    CRTCtrlPrint1Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
     
    pDC->Rectangle(1*r,1*r,800*r,-1100*r);//Print Area Rect
     
    if(pDC->IsPrinting())
    {
    DrawEditText(pDC);//Simple Edit box text
    DrawRichText(pDC);//My RichEdit box text
    }
    }
     
    #define IDC_REDIT 4001 //defining a resource ID
    #define IDC_EDIT 4002 //defining a resource ID
     
    void CRTCtrlPrint1View::RTCtrlCreate() //creates both Rich edit & Edit Controls
    {
    CRect m_temp;
     
    CClientDC dc(this);
    OnPrepareDC(&dc);
     
    //creating edit box in scroll view
    m_temp = m_edRect;
    dc.LPtoDP(m_temp);
    m_edit.Create(WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,m_temp,this,IDC_EDIT);
    m_edit.SetFont(&font,FALSE);
    m_edit.SetWindowText("Help Me! Thank u");
     
    //creating rich edit box in scroll view
    m_temp = m_redRect;
    dc.LPtoDP(m_temp);
    m_redit.Create(WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,m_temp,this,IDC_REDIT);
     
    //writing some text in richtext control
    CString str;
    str="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang2057{\\fonttbl{\\f0\froman\\fprq2\\fcharset0 Times New Roman;}{\\f1\\fswiss\\fprq2\\fcharset0 System;}}{\\colortbl ;\\red255\\green0\\blue0;\\red51\\green153\\blue102;\\red0\\green0\\blue255;}\\viewkind4\\uc1\\pard\\cf1\\i\\f0\\fs24 ThankYou\
    \\cf0\\i0 \\cf2\\b for\
    \\cf0\\b0 \\cf3 Trying\
    \\cf0 !\\b\\f1\\fs20 \\par }";
     
    EDITSTREAM es;
    es.dwCookie = (DWORD)&str;
    es.pfnCallback = RichEditStreamInCallback;
    m_redit.StreamIn(SF_RTF,es);
    }
     
    void CRTCtrlPrint1View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
    {

    CScrollView::OnPrepareDC(pDC, pInfo);
     
    // pDC->SetMapMode(MM_ANISOTROPIC);
    pDC->SetMapMode(MM_TWIPS);
    }
     

    void CRTCtrlPrint1View::DrawEditText(CDC *pDC)
    {
    CRect m_temp;
    m_temp = m_edRect;
     
    CString str;
    m_edit.GetWindowText(str);
    pDC->SetBkMode(TRANSPARENT);
    pDC->Rectangle(m_temp);
    //Draws with Fonts as we wish
    pDC->DrawText(str,m_temp,DT_WORDBREAK|DT_EXPANDTABS|DT_NOPREFIX);
    }
     
    //****************************************************************************
    // I want to draw the RichTextControl content in a specified rectangle on my
    // printing page (as i done with editbox control) using FormatRange function
    // with the different Font styles as in RichEditControl - HelpMe please!.
    // DrawRichText(CDC *pDC) -> could u solve the problem that i have in this
    // function ?..
    //****************************************************************************
    void CRTCtrlPrint1View::DrawRichText(CDC *pDC)
    {
    CRect m_temp;
    FORMATRANGE fmtRange;
    long lLineWidth;
     
    m_temp = m_redRect;
    // pDC->LPtoDP(m_temp);
    pDC->Rectangle(m_temp);
     
    lLineWidth = ::MulDiv(pDC->GetDeviceCaps(PHYSICALWIDTH), 1440,
    pDC->GetDeviceCaps(LOGPIXELSX));
     
    fmtRange.hdc = pDC->m_hDC;
    fmtRange.hdcTarget = pDC->m_hDC;
    fmtRange.rc = m_temp;
    fmtRange.rcPage = m_temp;
    fmtRange.chrg.cpMin = 0;
    fmtRange.chrg.cpMax = -1;
     
    m_redit.SetTargetDevice(pDC->m_hDC, lLineWidth);
    m_redit.FormatRange(&fmtRange, TRUE);
    }
    my MailID: cpbalaji2000@yahoo.com
     
    Balaji
    General...I need help on overwriting CWinApp PinmembervanjaESS7-May-03 11:25 
    GeneralProblems with VC++ 7 PinsussPaul Steane7-Mar-03 23:19 
    GeneralRe: Problems with VC++ 7 PinmemberPaul Steane6-Nov-04 10:12 
    GeneralAnother Bug/Oversite found PinmemberEldon Zacek1-Jan-03 19:30 
    QuestionHow to realize multipage printpreview in a D/V whose parent class is CStrollView? Pinmemberwilliam_shen1-Jan-03 3:26 
    AnswerRe: How to realize multipage printpreview in a D/V whose parent class is CStrollView? PinmemberRoger Allen2-Jan-03 1:41 
    Generalquestion about CPrintDialog and DEVMODE Structure Pinmemberlavocat2-Dec-02 1:21 
    GeneralGreat, but one more question PinsussLubin25-Oct-02 16:33 
    GeneralRe: Great, but one more question PinmemberRoger Allen21-May-04 2:58 
    GeneralBug... PinmemberMulot16-Sep-02 11:36 
    GeneralTool bar buttons are slow?! PinmemberMulot16-Sep-02 11:27 
    GeneralCrashes PinmemberBob Eastman13-May-02 12:14 
    GeneralRe: Crashes PinmemberRoger Allen14-May-02 3:24 
    GeneralWoops. You need this correction to avoid a memory leak PinmemberRoger Allen29-Apr-02 3:16 
    GeneralGood effort! PinmemberNish [BusterBoy]28-Apr-02 16:05 
    GeneralRe: Good effort! PinmemberRoger Allen28-Apr-02 22:32 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Terms of Use | Mobile
    Web01 | 2.8.150129.1 | Last Updated 28 Apr 2002
    Article Copyright 2002 by Roger Allen
    Everything else Copyright © CodeProject, 1999-2015
    Layout: fixed | fluid