HOME - - - - - Lazarus Tutorials TOC - - - - - - Other material for programmers

"Digression 1"- Printing hardcopy with Lazarus code

(Sidebar to main tutorial)

Page URL: lt3Nhardc-short-d1.htm

This page is "browser friendly". Make your browser window as wide as you want it. The text will flow nicely for you. It is easier to read in a narrow window. With most browsers, pressing plus, minus or zero while the control key (ctrl) is held down will change the texts size. (Enlarge, reduce, restore to default, respectively.) (This is more fully explained, and there's another tip, at my Power Browsing page.)

This is a "sidebar" to a longer discussion of how to use Lazarus to generate hardcopy. The link will return you to where the digression arose.

If this page will probably just be frustrating if you haven't come here from its "parent" page, the "longer discussion". (Not to be confused with the "longer-longer" discussion that the parent page derived from!)

What you see below is VERY NEARLY the code on wiki.freepascal.org's "Using The Printer".

The main tutorial, of which this is but a digression, explains much of the why and wherefore of the evolution of the following. This digression is here as a place to pick through it, line by line.

The code...

Here is what I will explain. It won't run on its own... just for a start, a number of variables are global, declared elsewhere in the code this comes from.

Special: The object called "Printer".

The "Printer" object was provided to the application when "Printers" was added to the uses clause.

Other "mysterious" things are probably global constants (prefix "k") or variables. (prefixed with a Hungarian notation system.)

procedure Tsvy002f1.Button1Click(Sender: TObject);
const
  kLeftmargin = 100;
  kHeadline = 'I Printed My Very First Text On ';
var
  YPos, LineHeight, VerticalMargin: Integer;
  SuccessString: String;
begin
  if PrintDialog1.execute then begin //SIGSEGV fix- 1 of 2 lines
  with Printer do
  try
    //Prepare the "paper"...
    BeginDoc;
    Canvas.Font.Name := 'Courier New';
    Canvas.Font.Size := 10;
    Canvas.Font.Color := clBlack;
    //Calculate the vertical coordinate of where the text will go.
    iPPLineHeight:=Round(1.2 * Abs(Canvas.TextHeight('I')));
    iPPYPos:=4 * iPPLineHeight;
    //Put writing on "the paper"...
    sTextToPrint:='Hello hardcopy world ';
    //The following line is an unnecessary frill... but it
    //adds a bit to help you distinguish one test print from another...
         sTextToPrint:=sTextToPrint+DateTimeToStr(Now);
    Canvas.TextOut(iPPLeftmargin,iPPYPos,sTextToPrint);
  finally //If all of the above completed okay,
               //"EndDoc" will trigger the actual printing...
    EndDoc;
  end; //of "try... finally..."
 end; //SIGSEGV fix- 2 of 2 lines for this
end; //buProduceHardcopyClick

The discussion

You do understand the "try... finally..." control structure, don't you? (The link will take you, in a new tab, to the FreePascal explanation.)

If you have...

  try [[condition]]
    showmessage('a');
    OwnProc1;
    showmessage('b');
    OwnProc2;
    showmessage('c');
  finally
    showmessage('d');
  end;//of "try... finally"

... then when the code runs, the computer tries to do the stuff between the "try" and the "finally", but if it encounters a problem at any point, it skips ahead to "finally".

It will always do the code in the "finally" block.

You will always get the "a" message and the "d" message. You will also get the "c" message, if neither your "OwnProc" 1 or 2 threw up exceptions... like, for instance, an attempt to divide by zero. You will only get message "a", "b" and "d" if OwnProc1 went okay, but OwnProc2 didn't.

Even if OwnProc2 would have gone okay, you won't see message "c" if OwnProc1 didn't go okay.

If you are running code that is under development from within the Lazarus IDE, and certain types of problem arise, you will get a message, but will be able to carry on by pressing "continue". If you are running the code from the .exe, you won't see the message, but bits of your code will be skipped over.

("try... finally" has a useful cousin: "try... except...")

Overview

The procedure boils down to...

if PrintDialog1.execute then begin
   with Printer do

   try
     BeginDoc;
      [[Set some properties of Printer.Canvas]]
      [[Calculate some values we'll need]]
      [[Put what you want on the page in a string variable...]]
          sTextToPrint:='Hello hardcopy world ';

      [[Transfer the string to the printer's canvas, as a graphic...]]
          Canvas.TextOut(iPPLeftmargin,iPPYPos,sTextToPrint);

   finally
      EndDoc;
   end; //end of "try... finally"

 end; //of if.. then.. begin...
end; //of buProduceHardcopyClick

Details

if PrintDialog1.execute...

This gives you the probably-familiar dialog for choosing which printer to sent the job to. (The dialog almost any application produces when you ask to choose a printer for a job.) It will be annoying to have to click "okay" if you only have one printer or are happy with the default... but invoking the dialog is a kludge to spare the user the "SIGSEGV" problem.

with Printer do

This spares us putting "Printer." in front of "BeginDoc","Canvas..." and "EndDoc" non many following lines.

BeginDoc;

Makes a start towards the eventual goal. "Creates" a "blank piece of paper" to write on... but only, for now, inside the computer, i.e. inside the "Printer" object.

-----
Now we come to "[[Set some properties of Printer.Canvas]] ".
That consisted of...

Canvas.Font.Name:='Courier New';
Canvas.Font.Size:=10;
Canvas.Font.Color:=clBlack;

Nothing too difficult about these, I hope? But maybe they give you an idea of the things you can do! By the way... a little good news: setting Font.Size is the primary determinant of the size of your ink-on-paper result. Why am I talking about "good news"? The "bad news" is that when you come to "drawing", directly, on Printer.Canvas, with things like "moveto" and "lineto", you will be working in units that depend on what printer you have on your system.But You Can Do It. (You're already using them when you specify where text is to be put on the page.)

-----
Now we come to "[[Calculate some values we'll need]] ".
That consisted of...



-----
Now we come to "[[Put what you want on the page in a string variable...]] sTextToPrint:='Hello hardcopy world ';".
That consisted of...

iPPLineHeight:=Round(1.2 * Abs(Canvas.TextHeight('I')));
iPPYPos:=4 * iPPLineHeight;

Ah. Yes. I've been avoiding these two lines!

Take a step back with me. Remember: We're going to use "TextOut" in a moment, a procedure that takes some characters, and converts them to a graphic. The graphic goes "on" "something". (The Printer.Canvas, in this case.)

A simple TextOut command would be TextOut(10,20,'Hello'). That would put 'Hello' on the "something" 10 units across, 20 units down from the upper left corner of the "something". In the two lines of code in the demo, the one that calculates iPPYPos is going to go to the upcoming TextOut, as the second parameter. We'll come back to it in a moment.

Abs(Canvas.TextHeight('I') tells you, given the current property settings, how high the letter 'I' is, in the same units as TextOut uses.

iPPLineHeight won't change the size of the characters being printed. But if you want to print three "lines", using three "TextOut"s, using the previously fetched Abs(Canvas.TextHeight('I'), you can use that to set TestOut's second parameter to something suitable to put the line in the right place on the page. The 1.2* ("multiply by 1.2") is there to add a little space between the bottoms of the letters of the first row and the tops of the second row.

The "4" in the demo code merely puts the line, somewhat arbitrarily, on the fourth line of the Canvas.

Whew! Not "hard"... just a lot of detail to master.

And remember: We've decided to limit ourselves to doing one line at a time, and only sending lines that are short enough to "fit" if they start where we've said to start them. (You may want to do your early printing to hardcopy in a monospaced font!)

But also remember that Lazarus is kind... if you accidentally send a too-long line to TextOut, no harm will come of it... apart from some of your text being missing from the hardcopy!

-----
Now we come to "[[Transfer the string to the printer's canvas, as a graphic...]]
That was just...

Canvas.TextOut(iPPLeftmargin,iPPYPos,sTextToPrint);"

And I hope that all your work up to here... including learning what I said about TextOut in the main document (lt3Nhardc-short.htm) makes that pretty clear to you without further help?

-----
Then we have...

EndDoc;

That line will always run. (Because of how "try.. finally.." works.)

Until that runs, nothing will come out of the printer. The programmer and users can "do things" to the internal representation of that which is to be printed to their satisfaction. If all has gone well up to this point, the EndDoc will see that what's been specified gets printed.

Also, whether or not everything "went well", all "loose ends", etc, that arose when the program passed "Printer.BeginDoc" are tied off. (You will see discussion on the internet of using Printer.free, and similar. Don't. Don't "free" things you didn't "create". "The system" will take care of "free"s for things it "created".)

-------------------
After the "EndDoc" we're done! (^_^)

WHEW!





Onward...

You now have the basics of putting ink-on-paper from a Lazarus application!

Besides mere text, you can also put graphics on paper.

You "only" need to "draw" on Printer.Canvas in the usual way, before the EndDoc command... but that's a story for another time. Or "play" with it now! If you can draw on an image on the screen, you're 90% of the way to drawing on something to be printed.

I said you have the basics... and you do! But there are other things you will want to know. Return to where you were in the main essay. If you came here from there, you probably only need to close the tab you are currently reading. Alternatively, here's a link to the right place in the "parent" discussion of how to use Lazarus to generate hardcopy.





Footer

Search across all my sites with the Google search...

Custom Search


Use this to search THIS site.... (Go to my other sites, below, and use their search buttons if you want to search them.)

index sitemap advanced
search engine by freefind

Site Map    What's New    Search

The search engine merely looks for the words you type, so....
*    Spell them properly.
*     Don't bother with "How do I get rich?" That will merely return pages with "how", "do", "I"....

Please also note that I have two other sites, and that this search will not include them. They have their own search buttons.

My SheepdogSoftware.co.uk site.

My site at Arunet.


Ad from page's editor: Yes.. I do enjoy compiling these things for you. I hope they are helpful. However... this doesn't pay my bills!!! Sheepdog Software is supposed to help do that, so if you found this stuff useful, (and you run a Windows or MS-DOS PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!
Click here to visit editor's freeware, shareware page.

Link to Lazarus Tutorials main page

To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed! Please cite "lt3Nhardc-short-d1.htm".




Valid HTML 4.01 Transitional Page has been tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes.

AND passes... Valid CSS!

If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....