Printing Class Library

.

This update fixes most bugs reported by users and adds the following enhancements to the library

  • Tables can now have more than 1 visible print line. I.E. Multiline tables both static and virtual
  • There is a rotated text function to print text oriented thru 360 degrees of rotation
  • There is a static function to set page orientation on a page by page basis
  • There is a function to retrieve the device driver name currently in use
  • There is a function to place a user defined function into the printing logic to provide the ability to write form type programs where the actual data is not available until runtime. ( see Demo)
  • The reference is now available in both html and rtf ( see referenece.rtf or reference.html )

What's in the works

  • A parser and the ability to save and retrieve forms from disk.
  • The ability to use and print data from various controls in a formatted style. List, tree, and rich text controls are being evaluated and some other people have sent me some code but I have not had time to incorporate them yet.
  • Database connectivity to make report writing easier. If I do it it will be thru a virtual function that can be overridden to handle different databases. I use Codebase++ almost exclusively due to speed, reliability, and size issues. If anyone has any thoughts along this line let me know.

Before jumping into the description of the classes I would like to say a few things here and not repeat them later over and over. These classes use either MM_TEXT or MM_ANISOTROPIC mapping modes. If you know about mapping modes great, if not, don't worry. I'm not going to use the terms again. If interested see the constructor for CPage for the dirty details. All routines used to output text need at least two parameters to form a point of location. All location references in these classes use 0,0 to represent the upper left-hand corner of the output. As the first number grows larger the output goes down the page. As the second grows larger the text goes to the right. If you pass a double as a location reference the classes ASSUME you are using inches as a unit of measurement. This is the easiest and safest route to go because then you really can forget all about the mapping modes. If you wish to use the low-level route and specify the location to the nearest pixel use the MM_TEXT mode and have fun. However, be aware that some printer drivers will lie to you and the output will look considerably different than anticipated. If this is the case and you still need to have exact placement use MM_ANISOTROPIC mode ( the default mode ) and change the 1000 by 1000 logical units in the constructor to suit your needs.

This class library is designed to provide printing and print preview capabilities to applications developed using the Microsoft) Foundation Class Library. In our business we have need to emulate many pre-printed business and insurance forms. In some cases the client wishes us to print the entire document and in others just fill in the fields with information gathered or generated by the application. There was no commercial solution that we could find to do this so we started from scratch. It was an interesting journey.

There is probably no portion of MFC programming that is as mis-understood and poorly documented as printing. Most books and training films give it very short thrift and then it's on to the flashy GUI stuff we all love. Lot of programs resort to using a commercial report writing tool to handle simple printing chores and others simply direct screen drawing to the printer DC in a crude kind of screen print. We found this unacceptable.

The classes are divided into two logical sections. The file Cprinter.cpp holds the low-level printer primitives. Suprisingly there are only three of them


virtual int PrintText(PRTTYPE *ps,double LineSpacing);

virtual void DrawLine(PRTTYPE *ps,int LineSize);

virtual void DrawRect(PRTTYPE *ps,int LineSize);

These are all that we needed to provide a large amount of printing options. If you wish to add more low-level capabilities this is the place to put them.

The higher level constructs are in the file Cpage.cpp. The classes here are

  • CPage represents a page of printed output. MFC printing architecture provides for printing on a page by page method. CPage holds and manipulates data concerning that page. There are member functions to output text, draw boxes and lines, create and use moveable print regions, and create and use tables of data. Fonts and text attributes can be changed freely and newspaper type columns are supported. Much of this functionality is provided by helper classes that are created by CPage as needed and used. These classes are
  • CTable represents a table of data. A table is much like a grid. It has rows and columns. It can have vertical and/or horizontal separations, a border, and a title. Each column in the table is composed of a class that holds a description of the column. This is the header for that column and the width of the column. Please see the documentation and the sample code for the use of tables. In essence the use is really simple. You create a variable of type CTABLEHEADER either on the stack or the heap and set its member variables to describe the table you wish to use. You the pass a pointer to the filled in structure to CPage via the CPageTable(CTABLEHEADER*) function. The table is constructed and displayed at this time. Data may be added to the table using overloaded functions in CPage that are the same as used to print to the page. Look at the documentation and the sample source code for details
  • CPrintRegion represents a sub region of the printed page that is to be treated as a single object. This region may contain textual data, columnar output, check boxes, and graphics but is to be treated as a single unit. The region can have a border and a title id desired. Move the region and all its contents move with it. This allows story boarding of the page. Since most forms have areas that are logical units these can be considered as a print region. Then when the client asks if you can move this here and that there it is a simple task of placing the new co-ordinates in and recompiling. Everything moves with the region. CPageCreateRegion() will return a pointer to a newly created CPrintRegion class. Since CPage actually creates this pointer it keeps an internal list of pointers and deletes the when the CPage~CPage() destructor runs. DO NOT DELETE A CPrintRegion * passed to you from CPage as a page fault may occur when the destructor runs.

All of these classes (CPage CTable CPrintRegion ) are defined in Cpage.h and implemented in CPage.cpp. In order to implement the class functionality in your application include these files in your project and include the line #include "cpage.h" in any file using the classes. There is a RTF file titled REFERENCE.rtf included in the source code that contains more detailed information on the class members and their use.There is also a html file by the same name. Also a demo project is included. It contains sample code exercising most of the class members. This is a bare bones version of the library with most of the esoteric stuff taken out and the code simplified and cleaned up to make it as clear as possible. Everybody has to have their own little special thing and as time goes by the class starts getting bigger and bigger and interdependencies crop up. I think I have removed most of the interdependent code and all the obvious bugs that crop up during a re-write.

One thing that we learned from this is that it is possible to be to object oriented. At one time we had a CParagraph and a CSentence and a CTitle etc. It really just got to be more trouble than it was worth. We think we have hit a happy medium here. This code is being used as the basis for ad hoc report writers, data base output, forms generation, and several other tasks and has proven to be pretty stable. It has not been tested on Win3.1 but the original code was and was developed there so barring any MFC 32 bit stuff it should compile and run fine in 3.1.

I have added the ability to print disk based bit maps to the library. The function is PrintBitMap() and is documented in REFERENCE.rtf. Most of the code was taken from a sample program included with the compiler and modified to fit into this library. The print functions have the ability to print over the bitmap(s). This allows one to scan a form and later print it and place data on it or to place boilerplate printing in a bit map and print only those portions of the form you wish. It is also handy for printing company logos, letter head, etc.

This code snippet shows how the classes are used in the view class


void CMainViewOnPrint(CDC* pDC, CPrintInfo* pInfo)
{
        CPage* ps = new CPage(pInfo-m_rectDraw,pDC,MM_TEXT);
        if(PRINTWHAT==0) PrintForm1(ps);
        if(PRINTWHAT==1) PrintForm2(ps); // subform demo
        if(PRINTWHAT==2) PrintForm3(ps); // table demo
        if(PRINTWHAT==3) PrintForm3(ps); // bitmap demo
        delete ps;
        return;
}

Below are some small examples of how the classes are used.


void PrintForm1(CPage* pPage)
{
        double Row;
        //Print a bitmap
        ps->PrintBitMap(1.0,1.0,4.0,5.0,"MyBitmap.bmp"); 
        //Print a title
        Row=pPage-Print(0.0,0.0,TEXT_NORMAL|TEXT_CENTER,24,"Form Title");
        //create and use a print region
        CPrintRegion *Region1=pPage->CreateRegion(.5,0.0,1.5,3.9);
        Region1->DrawBorder();
        Region1->DrawTitle("Customer 
        Information",8,TEXT_BOLD|TEXT_CENTER|TEXT_RECT,FILL_NONE);
        Row=pPage->Print(Region2,0.0,0.01,TEXT_NORMAL|TEXT_SINGLELINE,9,"Name");
        Row=pPage->Print(Region2,Row,0.01,TEXT_NORMAL|TEXT_SINGLELINE,9,"Location");
}


//create and use a table
TABLEHEADER* pTable=new TABLEHEADER; 
pTable->PointSize=10;
pTable->LineSize=1; // default shown only for demo purposes
pTable->UseInches=TRUE;
pTable->AutoSize=FALSE;
pTable->Border=TRUE;
pTable->FillFlag=FILL_NONE;
pTable->NumColumns=5;
pTable->NumRows=12;
Table->StartRow=0.0;
pTable->StartCol=0.0;
pTable->EndCol=8.0;
pTable->ColDesc[0].Init(1.0,"Item #");
pTable->ColDesc[1].Init(3.0,"Desc.");
pTable->ColDesc[2].Init(1.0,"# Items");
pTable->ColDesc[3].Init(1.0,"Cost");
pTable->ColDesc[4].Init(1.0,"Ext Cost");
pPage->Table(pTable);    

//place information in a table
pPage-Print(pTable,0,0,12,TEXT_LEFT|TEXT_BOLD,"123-009");
pPage-Print(pTable,0,1,12,TEXT_CENTER|TEXT_BOLD,"Small Cray Computer");
pPage-Print(pTable,0,2,12,TEXT_CENTER|TEXT_BOLD,"2");
pPage-Print(pTable,0,3,12,TEXT_RIGHT|TEXT_BOLD,"22.10");
pPage-Print(pTable,0,4,12,TEXT_RIGHT|TEXT_BOLD,"44.20");

Download demo project - 105 Kb

Download source - 48 Kb



About the Author

Richard Stringer

C C++ ASM are my currrent languages of choice. Currently writing MFC apps for insurance companies

Comments

  • SNMP Problem

    Posted by keshu82_sh on 07/13/2005 05:02am

    can any one help me in SNMP using VC++

    Reply
  • Print the bgcolor properties that are set in a table

    Posted by Legacy on 09/15/2003 12:00am

    Originally posted by: Kim Weir

    I cannot get the bgcolor that is set in the table to print. Any advice?

    Thanks,

    Kim

    Reply
  • Setting number of pages before displaying Print Dialog

    Posted by Legacy on 09/03/2003 12:00am

    Originally posted by: Clive Minnican

    Hello,
    
    

    Is there any way of calculating and setting the max number of pages before displaying the print dialog?

    To clarify, I know you can set the max number of pages to a constant value in the OnPreparePrinting function ie.


    BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo)
    {
    pInfo->SetMaxPage(2);

    return DoPreparePrinting(pInfo);
    }

    but I need to be able to calculate the number of pages depending on whether the printer is set to portrait or landscape mode. This is where I have a problem since I cannot find out which mode the printer is in due to GetPrinterMode() needing a valid printer device context. I am therefore resorting to calculating the number of pages in the OnBeginPrinting() function.

    Another question regarding this issue is how can I update the number of pages in the dialog when the user goes into properties and changes printer mode from portrait to landscape or vice-versa?

    Any help with either of the above will be much appreciated.

    Clive.

    • Printer Driver

      Posted by keshu82_sh on 07/13/2005 05:06am

      Are u using DDK for developing printer driver

      Reply
    • I am developing the printer driver.

      Posted by notfineman on 05/08/2004 03:03am

      I think your code is good.

      Reply
    Reply
  • Printing rtf files without showing them

    Posted by Legacy on 08/17/2003 12:00am

    Originally posted by: Leon

    Hi!
    
    im trying to write program that prints rtf files form command line without opening window or with hidden window.
    please help me
    Leon
    10x

    Reply
  • http://www.ucancode.net

    Posted by Legacy on 02/21/2003 12:00am

    Originally posted by: happppp

    It's very useful!

    Reply
  • Crashes in real application

    Posted by Legacy on 02/13/2003 12:00am

    Originally posted by: Thomas R�nshof

    Hi, I've tried the demo and it works OK.

    But implementing the classes and testprints in my existing application, the program crashes. Except for PrintForm3 and PrintForm4. But here the page/paper is blank !!!

    Has anyone seen this before ?

    Reply
  • simple Example for printing from a Dialog?

    Posted by Legacy on 11/19/2002 12:00am

    Originally posted by: TimoL


    Hi,
    i am trying to print from a dialog.
    but i don't know how to get the PrintInfo (my first problem)...
    do someone already wrote a simple usage?!?

    thanks
    Timo

    Reply
  • Report generation from sql server

    Posted by Legacy on 08/07/2002 12:00am

    Originally posted by: Ramu

    Dear sir/madam,
    
    i have one doubt in sql. hope u wil clarify my doubts...

    i want to generate a report in sql server2000 and display it in IE(Internet Explorer). if it is possible, plz help me out by describing the solution.

    thanking u sir/madam

    Ram

    Reply
  • Bug (???) in the constructor of TABLEHEADER

    Posted by Legacy on 04/26/2002 12:00am

    Originally posted by: Tim

    First: sorry for my bad english

    Problem:
    SOMETIMES (only in the release NOT in the debug version) my program crashed, when i used the table-printing functions.
    I "debugged" the problem in the release version, and saw, that the pTable->EndRow member wasn't at zero, but the pTable pointer was new, made with pTable = new TABLEHEADER

    The fix for this problem was to add a line in the constructor of TABLEHEADER like

    EndRow = 0;


    btw: REALLY GREAT CLASS ;)
    Tim

    Reply
  • How to transact MM_TWIPS to MM_TEXT

    Posted by Legacy on 04/17/2002 12:00am

    Originally posted by: mylonestartear

    In my print.cpp I use MM_TWIPS and MM_TEXT mode,how i can transact logical unit (in MM_TWIPS) to logical unit (in MM_TEXT)?
    

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date