Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Code to Allow You to Print the Content of a CTreeCtrl

0.00/5 (No votes)
16 Mar 2003 1  
A base class that provides all the functions you need to print a CTreeCtrl

Sample Image - examplePreview.gif

Introduction

Once again, I present a small printing class I recently developed to allow me to print the content of a CTreeCtrl. The code in itself is contained within a small class from which you can inherit your view/dialog that needs to be able to print the content of a CTreeCtrl.

So How Do We Use It?

To gain all the functionality you will require to print the content of a CTreeCtrl, you need to inherit the class that will be handling the actual printing from the supplied class TreeCtrlPrint.

#include "TreeCtrlPrint.h"

class CExampleView : public CFormView, TreeCtrlPrint
{

Doing this gives you access to the following functions in the class:

HTREEITEM GetNextTreeItem(const CTreeCtrl& treeCtrl, HTREEITEM hItem)

You use this function to iterate through the tree control in the order of all items as they would be drawn if all nodes in the tree control have been expanded. This lets you plot all the items in the correct order.

void DrawTreeItem(const CTreeCtrl& treeCtrl, HTREEITEM hPrintItem, CDC *pDC, CRect rect, CWnd *pWnd)

This function actually does the drawing of the specific tree item, you need to pass in the handle of the tree item to print, the rectangle on the target DC which you want to print the output into. Some assumptions are made about the DC in that it will have the correct font selected into it to render with and the height of the rectangle supplied will be used as the size of an icon/image when plotted.

ExpandAll(CTreeCtrl& treeCtrl)

This function will automatically expand all tree items with children.

Typical Printing Code

You have to do some work when printing the content of the tree control:

Select the Correct Font

If you look in the example application, you will see that I make use of the font being used by the tree control for printing, but just scaled correctly for the DPI of the printer:

CFont        font ;
LOGFONT        lf ;

pTreeCtrl->GetFont()->GetLogFont(&lf);
// This aims to get the same size font for the printer as in use by the control 
// on the screen printer resolution
lf.lfHeight = -MulDiv(abs(lf.lfHeight), pDC->GetDeviceCaps(LOGPIXELSY), 72);
VERIFY(font.CreateFontIndirect(&lf));
pDC->SelectObject(&font) ;

Get the Number of Items that Can Fit on a Page

Once you have the correct font selected, you can calculate how many items can fit on a page, and from there, calculate the number of pages required to print the tree control content.

CString text("A") ;
CSize cs = dc.GetTextExtent(text) ;
linesPerPage = abs(pInfo->m_rectDraw.Height() / cs.cy) -1;
if ((numTreeItems % linesPerPage) != 0)
{
    // we need to include the partial page
    numberOfPages++;
}
// Add in the whole pages
numberOfPages += (numTreeItems / linesPerPage);

The Actual Print Loop

When printing, your OnPrint() function gets called once per page of output, so we may need to navigate to the correct start position in the tree control before we start to print the tree items.

// navigate to correct start position, if printing the 2nd or later page

HTREEITEM hPrintItem = pTreeCtrl->GetRootItem();
for (int i = 0 ; i < linesPerPage * currentPage && i < numTreeItems ; i++)
{
    hPrintItem = GetNextTreeItem(*pTreeCtrl, hPrintItem);
}

Once we're at the correct start position in the tree, we just keep printing items until either we run out of items or page space:

// continue printing from this point onwards until we run oot of page area

for (i = linesPerPage * currentPage ; 
    (i < numTreeItems) && (i < (linesPerPage * (currentPage + 1))) ; i++)
{
    // calculate the rectangle for this tree item
    CRect    rect(pInfo->m_rectDraw.left + (cs.cx * 2), 
                  pInfo->m_rectDraw.top + (cs.cy * line_number), 
                  pInfo->m_rectDraw.left + pInfo->m_rectDraw.Width(), 
                  pInfo->m_rectDraw.top + (cs.cy * (line_number + 1)));
    DrawTreeItem(*pTreeCtrl, hPrintItem, pDC, rect, this);
    line_number++;
    hPrintItem = GetNextTreeItem(*pTreeCtrl, hPrintItem);
}

This code uses one extra variable currentPage which is taken from pInfo->m_nCurPage - 1, as we need a 0 based page numbering scheme to correctly work out the starting print item for following pages.

Well, that's all there is to it really.

Problems Encountered

As I said earlier, this is recently developed code for one of my applications. I ported it across for the CodeProject article and setup the example application. It was then that I found out that my code did not work properly for cases where you had more than 1 root item (my app only has 1 root item). My code was indenting the following root items and generally making a mess of things, so in a way, this article improved my application...

History

  • 17th March, 2003

    A bug fix for the GetNextTreeItem() function as reported by bhtang - should now work correctly with any type of populated tree. The example application was updated to call UpdatePrinterSelection(TRUE); in InitInstance() so that a default printer will be automatically selected at start-up, as suggested by Michael A. Rusakov

    A new function ExpandAll(CTreeCtrl& treeCtrl) was added to the class to expand all tree items which have children.

  • 5th March, 2003 - Initial version

Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here