Link to home
Start Free TrialLog in
Avatar of BudVVeezer
BudVVeezer

asked on

Printing Question

When I print, and the text is less than a page long, everything works fine.  But when it's over a page long, it just cuts off the text, and doesn't start a new page.  I am programming in C(not MFC or C++), using Win32 API.  Do I have to do page breaks manually?  If I do, how can I tell when to do the page break?  The function for printing takes a LPTSTR as it's only parameter...  Thanks!

~Aaron
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Answers2000
Answers2000

jkr types faster...so I'll submit as comment


1. You have to do the page breaks manually, use the EndPage API call to force a page break

2. When you draw the text you need to keep track of when you reach the bottom of the page.  There are 2 obvious ways to do this :-

(a) Use TextOut (or other API) to draw the text a line at a time (e.g. if you have a long string with line breaks, you break the string yourself before parsing).  You can calculate the lenght of a string of text using GetTextExtent. Basically
- keep a variable of current pos on page.  
- TextOut a line at current pos
- increase the pos on the page by the height of the text
- if reached bottom of the page, do EndPage, then reset variable to 0 to go to top of next page
- repeat till you run out of text

This is the way I like to print, but it is more work.  With this approach you can control the layout exactly (e.g. if you don't want to split paragraphs over a page break) by varying the algorithm appropriately


or
(b) Use DrawText.  There is an option DT_CALCRECT which calculates the size of the rectangle required to fit the text.  So you call this to get the rect size, then output page 1 using a normal DrawText.  If not all the rectangle can fit on the page, do EndPage, and do DrawText again with the y-coord offset to ( -1 * page_height ), if still some left do EndPage then do DrawText again if the y-coord of (-2 * page_height), etc.
Avatar of BudVVeezer

ASKER

I am currently using DrawText, and would like to continue doing so.  Answers2000 ~you're on the right track, but when I tried doing it your way, it didn't work.  Could you by any chance post some sample code as to how to print w/DrawText?  Right now, it realizes that there are more than one pages, and it goes through the loop the appropriate amount of times, it just doesn't print the right stuff after the first page(page one still prints fine though).

~Aaron
Aaron like I say I use method (a) so I don't have sample code with DrawText sitting around on my hard-disk.  (not sure I have publishable C/API sample code on HD disk as I mostly use MFC nowadays)

Why not post your code and I'll tell you how to correct it.

BTW you should make a decision on jkr's answer...he (or others) may not be aware that you still have questions (I myself don't generally look at locked questions always)
Well, i am aware, and i'd suggest that you post the code also...
void PrintSelections(LPSTR String)
{
      DOCINFO            di;
    PRINTDLG      pd;
      RECT            r, Heading;
      int                        i, j = 0;

      memset ((void *) &pd, 0, sizeof(PRINTDLG));

    pd.lStructSize = sizeof(PRINTDLG);
    pd.hwndOwner   = NULL;
    pd.Flags       = PD_RETURNDC;
    pd.hInstance   = NULL;

      if(PrintDlg(&pd) == 0)      return;

         Heading.top = MARGIN;
      Heading.bottom = MARGIN + 500;
      Heading.right = GetDeviceCaps(pd.hDC, HORZRES) - MARGIN;
      Heading.left = MARGIN;

      i = DrawText(pd.hDC, String, strlen(String), &r, DT_CALCRECT);
      if(i > (GetDeviceCaps(pd.hDC, VERTRES) - MARGIN))
            j++;
      
      r.top = Heading.bottom + MARGIN;
      r.bottom = GetDeviceCaps(pd.hDC, VERTRES) - MARGIN;
      r.right = GetDeviceCaps(pd.hDC, HORZRES) - MARGIN;
      r.left = MARGIN;

      di.cbSize = sizeof(DOCINFO);
      di.lpszDocName = "Test Printing";
    di.lpszOutput = (LPTSTR) NULL;
    di.lpszDatatype = (LPTSTR) NULL;
    di.fwType = 0;

      StartDoc(pd.hDC, &di);
      for(i = 0; i <= j; i++)
      {
            StartPage(pd.hDC);

            r.top = Heading.bottom + MARGIN * -i;
            DrawText(pd.hDC, String, strlen(String), &r, DT_LEFT | DT_WORDBREAK);
            String = "";

            String = "Repnet 3 Call Report";
            DrawText(pd.hDC, String, strlen(String), &Heading, DT_CENTER | DT_WORDBREAK);

            EndPage(pd.hDC);
      }
      EndDoc(pd.hDC);
}

Please keep in mind that I was TIRED when I wrote this, and so it may make no sense.  =o)  I want each page to have that heading(hence the heading rect, etc) and then fit the string below it.  Thanks, to both of you!

~Aaron
If you could post the TextOut source code, that would work too, I can always rework the function...  I have been hacking around on this one for a while now, and am quite lost.  Answers, you answer makes sense, but I don't understand how I am supposed to change the y-coord.....do you mean change the rect.top value?  I tried doing that....but to no avail.  Grr, this is one of those things where I know I am doing something VERY stupid, but can't figure out what!  =o/  Thanks for you help, both of you!

~Aaron
Well, in the 'good(?) old times' of Win3.x i used 'TextOut()' for this task also... and changing the y-offset is indeed changing r.top...
See, the thing is, if I do it via TextOut, that means I have to parse a complicated string...and I guess I am just lazy.  =o)  I fixed some of the code so that it's less messy, and easier to work with(I think), I'll post it.  It still doesn't print right.  It prints the correct amount of pages(though that's not very well tested), but it prints the SAME stuff on every page..  =(  Please help!

~Aaron
void PrintSelections(LPSTR String)
{
      DOCINFO            di;
    PRINTDLG      pd;
      RECT            r, Heading;
      int                        i, j = 0;
      LPSTR            pHeading = "Repnet 3 Call Report";

      memset ((void *) &pd, 0, sizeof(PRINTDLG));

    pd.lStructSize = sizeof(PRINTDLG);
    pd.hwndOwner   = NULL;
    pd.Flags       = PD_RETURNDC;
    pd.hInstance   = NULL;

      if(PrintDlg(&pd) == 0)      return;

         Heading.top = MARGIN;
      Heading.bottom = MARGIN + 500;
      Heading.right = GetDeviceCaps(pd.hDC, HORZRES) - MARGIN;
      Heading.left = MARGIN;

      i = DrawText(pd.hDC, String, strlen(String), &r, DT_CALCRECT);
      
      r.top = Heading.bottom + MARGIN;
      r.bottom = GetDeviceCaps(pd.hDC, VERTRES) - MARGIN;
      r.right = GetDeviceCaps(pd.hDC, HORZRES) - MARGIN;
      r.left = MARGIN;

      j = i / (r.bottom - r.top) + 1;

      r.bottom = i;

      di.cbSize = sizeof(DOCINFO);
      di.lpszDocName = "Test Printing";
    di.lpszOutput = (LPTSTR) NULL;
    di.lpszDatatype = (LPTSTR) NULL;
    di.fwType = 0;

      StartDoc(pd.hDC, &di);
      for(i = 0; i <= j; i++)
      {
            StartPage(pd.hDC);
            
            if(i > 0)
                  r.top *= -i;
            
            DrawText(pd.hDC, pHeading, strlen(pHeading), &Heading, DT_CENTER | DT_WORDBREAK);
            DrawText(pd.hDC, String, strlen(String), &r, DT_LEFT | DT_WORDBREAK | DT_EXPANDTABS);

            EndPage(pd.hDC);
      }
      EndDoc(pd.hDC);
}

Well, i'm not surprised that there's the same stuff on every page, as 'String' isn't changed within the loop...
How am I supposed to keep track of what printed?  This is my first attempt at programming anything for printing..so I'm sorry that I am asking such dumb questions.

~Aaron
Well, you could e.g. use a 'static' local variable in the printing function that keeps track how many lines have been printed, and when the maximum is reached, 'EndPage()' is called and the variable is reset...
um, I guess I'm at a loss here....could you post some sample code on that...?  Because, as I understand it, DrawText takes the string you give it, and puts the entire string in the rect...  Boy, before this problem, I used to think I was a programmer..  :o)  Sorry for all the trouble!

~Aaron
OK, there's a little example (just patched it together to illustrate what to do, not guaranteed to work and partly 16 bit infected):

BOOL      bTextAvail = TRUE;
dwExtent  = GetTextExtent(hDC,"0",1);

nX=(int) (dwExtent&0x0000FFFF);
nY=(int)((dwExtent&0xFFFF0000)/0x10000);


while ( bTextAvail)
{
 for(i=0;i<uLinesPerPage;i++)
     {
      if (pcLineEnd=strstr(pcLineStart,"\r\n"))
        uLineLength=pcLineEnd-pcLineStart;
      else
        uLineLength=strlen(pcLineStart);

      TextOut(hDC,nX,dLineDist*nY*i+nY/4, // print with a little bit offset from frame: nY/4
            pcLineStart,uLineLength);

      if (!pcLineEnd)
      {
         bTextAvail = FALSE;
       break;
        }

      pcLineStart=pcLineEnd+2;
     }
 EndPage( hDC);
}
I won't be able to get back to this problem until Monday, as I am at home for the weekend, and have no printer at home..  =(  I'llget back to you though!

~Aaron
OK, have a nice weekend! ;o)
I'm going to give you the points now, because you deserve them after all the crap I've been making you do!  But please, do help me if I leave some comments.  =o)

~Aaron