Creating a Printing Class

Printing line-by-line without a Document/View framework

.

Environment: tested on VC6 SP4 and VC7

Introduction

Do you still remember the times of the LINE printer (a dot-matrix printer)? Printing was still simple in these times. You simply sent print lines to the printer and lines in exactly this order were printed out. Searching for a way to use this technique, I created the class "CPrivatePrint". This class gives you the possibility to do exactly this and more.

This class works much like a old line printer. There is a "print-cursor" that moves downward with each printed line. It is as though you are printing on an endless strip of paper. The class ensures that the text is divided correctly on single sheets.

For example: You have to print a couple of lines of text in a desired font. With the CPrivatePrint class, you send lineprints. That's all. If you need to arrange the text on two or more pages, the class does it for you. You only have to set the desired margins. Therefore, the main function of the class is "print()", which sends the text line.

Although with this class line for line is printed, it is also possible to position the print cursor at any time and let it continue the printing at this position (use the SetHPos() function to do this).

You don't have to think about font handling. To use different fonts, you add the desired fonts with AddFontToEnvironment(). With SetActiveFont(), you switch between the fonts during the printing.

Some Features

  • Printer selection is optional. (You can use the Windows printer selection dialog to select a printer or set a printer manually.)
  • Supports header and footer lines.
  • Supports bitmap printing.
  • Supports up to 10 different fonts in one document.
  • Supports font escapement.
  • Used fonts can be printed in bold and/or big versions.
  • For printer selection, you can use your own created dialog.

Using the Class

Here is the typical way to use the class:

  1. Include PrivatePrint.cpp and PrivatePrint.h into your project.
  2. Declare an object of CPrivatePrint.
  3. Call the member function Dialog() to let the user choose a printer and to initialize the object.
  4. Call the member function StartPrint(). This function MUST be called immediately after Dialog(), before other class functions are called. It creates the print document in the printer spooler. At the end of all printing, EndPrint() must be called to release it.
  5. Add the fonts that are needed with the member function AddFontToEnvironment(). Principally, it is enough to generate one font. The function returns a handle of the type HPRIVATEFONT, which then is needed for various other member functions. For each necessary font, the function must be called once. There are only 10 different fonts possible.
  6. Adjust the margins and the line spacing (dots between the print lines) with the member functions SetMargins() and SetDistance().
  7. If a header and/or a footer line is needed, the member function ActivateHF() must be called. See a description about this further down in this text.
  8. Call member function StartPage() to begin a new page. If the page ends, call EndPage(). Between these two functions, you place the line printings. Should it be necessary to print more lines than fit on one page (between the call of these two functions), the class ensures that EndPage() is called followed by a StartPage() automatically. A possibly necessary header and/or footer line is created automatically (if wanted). Normally, you use this function only once, at the start and the end. But if it is neccessary for your printing, you can create a new page every time by using EndPage() and StartPage().
  9. Lines are printed with the function Print(). With lf(), blank lines are produced. Further functions are:
    Function Description
    SetFace() Adjusts the appearance of a font
    SetActiveFont() Changes the font
    SetEscapment() Changes the writing direction
    Line() Creates a line
    InsertBitmap() Inserts a bitmap
    ... and so forth  
    All functions are explained in the remarks in the cpp file.
  10. Call the member function EndPrint() to release the document in the spooler.

Some Words About Header/Footer Lines

If you need a header or a footer, or both, you have to create a callback function, such as this:

void HeaderFooter(CPrivatePrint*prt,int page,bool hf)
{
}

With CPrivatePrint::ActivateHF(), you say the class that has to call this callback function each time a header or footer line is neccessary. In the hf parameter, you get "true" if the header has to be written, and "false" if the footer has. The *prt pointer gives you a pointer to your CPrivatePrint-Object, which is calling the callback function.

If you are using a footer line, think that the bottom margin includes the height of the footer line. For example, if your footer needs 100 points of height, then your bottom margin should equal or be greater than 100.

Here is an example. It uses the class to print a selected text file. In the header of the printing, the name of the file is printed. In the footer, there is a page counter. Also, there is a bitmap logo in the footer. The example also shows the use of a header/footer line function:

void PrintText()
{
  CPrivatePrint  prt;
  HPRIVATEFONT   hFont;
  FILE           *f1;
  CFileDialog    dlg(TRUE,_T("txt"),NULL,OFN_HIDEREADONLY |
                     OFN_OVERWRITEPROMPT,"Text Files (*.txt)|
                     *.txt||");
  char           cBuffer[1024];

  // get the file
  if (dlg.DoModal() != IDOK) return;

  g_strFileName = dlg.GetFileName();

  // open the file
  if ((f1 = fopen (g_strFileName,"r")) == NULL) {
    AfxMessageBox (_T("can't open the file"));
    return;
  }

  // initializing the class and printer selection
  prt.Dialog();

  // create the print document in the spooler
  prt.StartPrint();

  // Adding the arial font to the class
  hFont = prt.AddFontToEnvironment("Arial");

  // set margins and line spacing
  prt.SetMargins(300,400,500,300);
  prt.SetDistance(20);

  // activate a header and footer line
  prt.ActivateHF(HeaderFooter);

  // now start a page
  prt.StartPage();

  // start printing the lines
  while (fgets(cBuffer,1024,f1)) {
    CUT_LF_AT_THE_END(cBuffer);
    prt.Print(hFont,cBuffer,FORMAT_NORMAL);
  }

  // now end the page
  prt.EndPage();

  // close the print document and release it in the spooler
  prt.EndPrint();

  fclose (f1);
}

void HeaderFooter(CPrivatePrint*prt,int page,bool hf)
{

  if (hf)    // header line is wanted
  {
    prt->Print(prt->GetActiveFont(),g_strFileName,FORMAT_CENTER);
    prt->lf(prt->GetActiveFont(),1);
  }
  else
  {
    CSize  dim;
    CRect  margins;
    CString strBuffer;
    prt->GetDrawDimension(dim);
    prt->GetMargins(margins);
    prt->SetHPos(dim.cy-margins.bottom);
    strBuffer.Format ("Seite %d",page);
    prt->Print(prt->GetActiveFont(),strBuffer,FORMAT_CENTER);
    prt->InsertBitmap(IDB_LOGO,FORMAT_RIGHT);
  }
}

Downloads

Download demo project - 68 Kb
Download source - 10 Kb


Comments

  • Centering bug fix

    Posted by mschifter on 01/31/2007 10:04am

    Hi,
    
    This is a timesaving class, but text was not centering for me on the page. I traced this down to line 367 in PrivatePrint.cpp. Change:
    
        lx += m_DimDraw.cx/2 - Size.cx/2;
    to:
        lx = m_DimDraw.cx/2 - Size.cx/2;
    
    and this should fix the problem.

    Reply
  • Solution to one line per page problem....

    Posted by aschon on 05/09/2006 04:28pm

    Let me start by saying this class worked wonderfully and has performed 
    well so far in the app I am using it for. It has likely saved me hours over 
    using other alternatives. On with the problem/fix....
    
    m_Abstand is not being initialized.
    
    Reason for one line per page:
    When the calculation for end of page occurs, such as in Print() right before 
    the text is written, the page would break or not break after every line based 
    on the value left in m_Abstand at initialization. After initialization of the 
    PrivatePrint object every line written with that object either would or would 
    not be written on its own page based on the (random) initialization value. 
    
    Workaround:
    Call SetDistance() to provide the number of points between lines after object creation.
    
    Fix:
    Update code base to provide a reasonable default in the constructor, such as:
    m_Abstand = 5;

    Reply
  • How to control Font Size using this class

    Posted by wuwei on 01/06/2005 12:37am

    Hi, I want to print a text file using this class, but I want to print using different Font Size different rows. How to Realize it? Thanks.

    Reply
  • How to get the printer status

    Posted by Namal on 10/21/2004 08:24am

    Hi Guys,
    
    I wish to know how to get the printer status from an MFC application.
    
    I have tryed with querying the jobs for the printer and then get the status as follows
    
    	if (!EnumJobs(hPrinter,
    		   0,
    		   pPrinterInfo->cJobs,
    		   2,
    		   (LPBYTE)pJobStorage,
    		   cByteNeeded,
    		   (LPDWORD)&cByteUsed,
    		   (LPDWORD)&nReturned))
    	{
    	   free(pPrinterInfo);
    	   free(pJobStorage);
    	   pJobStorage = NULL;
    	   pPrinterInfo = NULL;
    	   return FALSE;
    	}
    
    But even when the printer is offline the status returned is always READY. 
    
    If you have some idea of this please help me.
    
    Thank you.

    Reply
  • PrivatePrint is working in my developements

    Posted by rgimilio on 03/09/2004 01:13pm

    I have incorporated PrivatePrint class in my MFC dialog based applications. It works. I have derived some private utilities for : - printing the content of a multiline edit control, - printing the content of a ListBox control Thanks for all.

    Reply
  • HELP! works differently in debug than in release !!!

    Posted by Legacy on 06/26/2003 12:00am

    Originally posted by: sfraden

    Odd problem, I have used this class all over my program, with great success, however in this one module, it prints each line on a seperate piece of paper, all well before endpage is ever called.  Now if I put it in debug mode and trace it out, it will work perfectly every time, I am really stumped!  Here is a snippet of the code...
    
    

    CPrivatePrint prn;
    HPRIVATEFONT hfont,bfont;

    prn.Dialog(); //chjoose printer to print to
    prn.StartPrint();
    hfont=prn.AddFontToEnvironment("MS Sans Serif");
    bfont=prn.AddFontToEnvironment("Comic Sans MS Bold",12,20);
    prn.SetActiveFont(hfont);
    m_bar.SetStep(1); //sets the bar for 100 steps


    int month=sp.m_month;
    int tripcount=1,plines=0;
    CString casinoname=sp.m_casinoname; //bring over the vars
    CString buff,idbuff,dbuff,pbuff,sbuff;
    CStdioFile fp;

    prn.StartPage();//begin job spooler for printing

    prn.SetActiveFont(bfont);
    prn.SetFace(bfont,FACE_BIG);
    prn.Print(bfont,"INDEPENDENT REP",FORMAT_CENTER);
    //prn.lf(1);
    prn.SetActiveFont(hfont);
    prn.Print(hfont,"COMMISSION ADJUSTMENT REQUEST FORM",FORMAT_CENTER);
    //prn.lf(1);
    prn.SetActiveFont(bfont);
    prn.Print(bfont,casinoname,FORMAT_CENTER);
    //prn.lf(1);
    prn.SetActiveFont(hfont);
    prn.Print(hfont," PLAYER ACCOUNT BIRTHDAY DATES",FORMAT_NORMAL);
    prn.lf(1);

    for(int c=0;c<indexarray.GetSize();c++) {
    buff=indexarray.GetAt(c); //load buff with player
    idbuff=buff.Mid(buff.ReverseFind(',')+1,buff.GetLength());//idbuff now = folder number
    buff.Format("%s%s\\trip%d.rec",recordpath,idbuff,tripcount);// got player pid in idbuff, open that players file up

    UpdateData(TRUE);
    hardnum=(c/total)*100;

    Reply
  • Please help me for online printing

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

    Originally posted by: azeem shaik

    -------------------------------------------------

    1.online printing: when ever user enter one Item information it should print imediately, the user complete the sales invoice then i have to call EndPage() function,so that i can cut the paper.
    -------------------------------------------------

    i want to print line by line,i have done this through ms-dos.

    i want to do through MFC.
    i want to print without calling EndPage() function.because EndPage() function is cutting paper(printer had autocutter). it is ending my task

    --------------------------------------------------

    Reply
  • Useing this code in Visual Basic 6.0

    Posted by Legacy on 04/05/2003 12:00am

    Originally posted by: Ritesh

    Hi,

    Could u tell me how could i use this code in vb6 and print a full length text file using this
    thanks

    Reply
  • How to add watermark option ot this

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

    Originally posted by: satya

    Hi i would liekt add the water mark option to the print dialog and also the optional caption for Watermarking hwo do i do that

    Reply
  • printing list ctrl which variable column width with dialogbox

    Posted by Legacy on 01/29/2003 12:00am

    Originally posted by: praveen

    hello sir
    i need to print listctrl which has variable number of columns and width of each column is variable.please help me

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • On-demand Event Event Date: October 23, 2014 Despite the current "virtualize everything" mentality, there are advantages to utilizing physical hardware for certain tasks. This is especially true for backups. In many cases, it is clearly in an organization's best interest to make use of physical, purpose-built backup appliances rather than relying on virtual backup software (VBA - Virtual Backup Appliances). Join us for this webcast to learn why physical appliances are preferable to virtual backup appliances, …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds