Using the printer/ja

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) 日本語 (ja) polski (pl) 中文(中国大陆)‎ (zh_CN)

はじめに

Lazarus/FreePascal での印刷は簡単です。しかしながら、いくつかのステップを踏む必要があります。第一ステップは共通です。その次からは、さまざまな進んだ印刷技法を学べるようになります。この文書は、必要不可欠なステップをさまざまなネットのフォーラムや例から集めてきたものです。最初のステップの後で、実際に文書を印刷してみます。最後に、更に高度な印刷技法のヒントを提供します。

基本的なステップ

プリンタを使えるようにするには、次の段階を踏まなければなりません: You must do the following to be able to use printers:

  1. Printer4Lazarus パッケージを、プロジェクトが要求するパッケージに含める。
  2. Printers ユニットを、プログラムの uses 節に加える。
  3. 既に存在する Printer オブジェクトを使用する。

Printer4Lazarus パッケージを、プロジェクトが要求するパッケージに含める

Printer4Lazarus パッケージは基本的なプリンタを定義し、プラットフォームに依存しない印刷環境を提供します。さまざまなプラットフォームで、次の事が行えます。 The Printer4Lazarus package defines a basic printer and provides platform independent printing. The following can thus be used on various platforms.

Lazarus IDE で、次のようにしてください:

  1. プロジェクトメニューで、プロジェクトインスペクタをクリックします。ツリー表示のウインドゥが現れ、その中に、要求されたパッケージという枝があります。初期状態では、その枝にはLCLパッケージがあります。
  2. 追加ボタンを押します(ウインドゥ上部の+印ボタン)。
  3. 新規の要求 ページを開きます。
  4. パッケージ名リストボックスから Printer4Lazarus を選びます。
  5. OKをクリック。
  6. これで Printer4Lazarus要求されたパッケージに現れます。

Printers ユニットをプログラムのユニットの uses 節に加える

このステップは簡単で、こんなふうになるでしょう:

unit MainUnit;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Forms, Printers;

既存の Printer オブジェクトを用いる

ボタンを押したら文章を印刷するようにしたいとします。フォームに PrintBtn という名前でボタンを置き、OnClick イヴェントのところにこう書いてください:

procedure TForm1.PrintBtnClick(Sender: TObject);
const
  LEFTMARGIN = 100;
  HEADLINE = 'I Printed My Very First Text On ';
var
  YPos, LineHeight, VerticalMargin: Integer;
  SuccessString: String;
begin
  with Printer do
  try
    BeginDoc;
    Canvas.Font.Name := 'Courier New';
    Canvas.Font.Size := 10;
    Canvas.Font.Color := clBlack;
    LineHeight := Round(1.2 * Abs(Canvas.TextHeight('I')));
    VerticalMargin := 4 * LineHeight;
    // There we go
    YPos := VerticalMargin;
    SuccessString := HEADLINE + DateTimeToStr(Now);   
    Canvas.TextOut(LEFTMARGIN, YPos, SuccessString);
  finally
    EndDoc;
  end;
end;

先ほど基本的かつ単純と書きました。上記の例はちょっと複雑です。ボールドで基礎的なテキスト出力を行う方法に引き続き、書式を設定する例も示しています。

begin から end までの間に、こんなことが起きています:

  • Printer.BeginDoc によって、印刷が始まります。ですが、 Printer.EndDoc を実行するまでプリンタには何も送られません。
  • プチンタは描画に Canvas を用います。そこに描かれたものが、最終的に印刷されるページに表示されます。Canvas.Font は Canvas への出力に用いられるフォントオブジェクトです。すなわち、ここで指定されたフォント設定が後の TextOut 呼出しによってテクストを描画する際に用いられるわけです。
  • Canvas に描画するものはすべて、座標によって位置決めされる必要があります。そこで、テクストの垂直方向の位置を定めるために LineHeight を計算しています。水平方向の位置も同様に計算します。ここでは LEFTMARGIN に置くことにします。
  • テクストは TextOut 呼出しで描画されます。
  • Printer.EndDoc によって、この偉業がプリンタに送られます。

フォーラムによっては、PrintDialog(プリンタ選択ダイアログ)を呼び出さないとうまくいかないように書いてありますが、(もはや)そんなことはありません。

次のステップ

上述の基本的なステップを踏んだら、次の段階に進めます。読者には以下の宿題を出しておきましょう:

  • 紙に図形を描画する。
  • テクストをかっこ良くフォーマットする。
  • 他のプリンタを選択して結果を比べる。

Lazarus には、プリンタへの Raw 印刷を用いる例があります。次の場所をみてください。 $(lazarusdir)\components\printers\samples\rawmode\rawmodetest.lpi 他のプリンタを選択する例はこれです: $(lazarusdir)\components\printers\samples\dialogs\selectprinter.lpi

進んだステップ: コントロールの印刷

根本的には、プリンタオブジェクトは Canvas への描画を許し、その Canvas のイメジをプリンタに送るものです。上述の路線で進むなら、プリンタの canvas が持つメソッドを用いてテクストや楕円や菱形やなんかを描画していくことになります。

しかしながらこれは、立派なプログラマには到底興味を持たれるようなものではありません。あなたは今、完璧な CAD ソフトや画像ファイルのソータを書いているところで、あなたのプログラムが生んだ素晴らしい結果をプリンタに送りたいと思っています。完全なピクチャを Canvas メソッド呼出しの集団に翻訳するですって? とんでもない: すでにピクチャは手許にあるのです。

あなたがフォームに置くコントロールは一つ残らず、プリンタと同じように TCanvas オブジェクトにピクチャを描画しているのです。スクリーンからプリンタにピクチャを持ち込むために、これが使えます。

プレビュープログラムを書いているとします。まずフォームを作り、その上に TPanel を置きます。このパネルは、プレビューのすてきな灰色の背景となります。そのパネルの上に、page と呼ばれるもう一つの TPanel を置きます。この page は白色で、紙を表します。ページの大きさもすてきに変更可能です。

このページの上に TShape オブジェクトを一つおきます。例えばすてきな赤の、角が丸い長方形。さてここで、次のコードを PrintBtnClick イヴェントメソッドに置いてみてください:

MyPrinter.BeginDoc;
  page.PaintTo(myPrinter.Canvas, 0, 0);
MyPrinter.EndDoc;

何が起きるか:

  • BeginDoc が印刷を開始します(が、まだ何も送られません)。
  • page.PaintTo は先に作った紙を表す TPanel オブジェクトの出力をプリンタの Canvas に送ります。次のことに注意してください:
    1. PaintTo メソッドは、コントロールのヒエラルキーの中のどのコントロールのものも使いたければ使えます。
    2. PaintTo メソッドを持っていれば、どのコントロールからもプリンタに出力を送れるので、いろいろなことができます。画像ソータなら、TImage の出力をプリンタに送れるわけです。
    3. TCanvas には、矩形領域を他の Canvas にコピーするメソッドがあります。しかし、この機能はそのオブジェクトが実際に Canvas に描画する場合にのみ使えます。思うに、ほとんどのコントロールは実際の Canvas としてコンテナを利用しています。ですから、コントロールから矩形領域のコピーを行うことはできません。少なくとも、私の所ではだめでした。
    4. 印刷しようとするコントロールが可視であることを確認してください。不可視だと、何もペイントされず、プリンタにも送られません。
  • EndDoc によって、描画情報がプリンタに送られます。

And on we go: resizing

The printer uses a lot more pixels per inch on paper than the monitor uses pixels per inch on the screen. As a result, the output that is redirected from the screen to the printer ends up rather smallish on the paper. Scaling and controlling the layout is important for good looking output. It would be nice if you can have an exact sized copy of what you see on the screen.

For the moment we are not striving for the ideal, just for the idea. As said before, controls do not have their own canvas but rely on the canvas of a container or owner. However, there are components that have their own canvas. I chose TBitMap and then it works as follows.

procedure TForm1.PrintBtnClick(Sender: TObject);
var
  MyPrinter : TPrinter;
  myBitMap : TBitMap;
begin
  myBitMap := TBitMap.Create;
  myBitMap.Width := page.Width;
  myBitMap.Height := page.Height;
  page.BorderStyle:=bsNone;
  page.PaintTo(myBitMap.Canvas, 0, 0);
  page.BorderStyle:=bsSingle;
  //
  MyPrinter := Printer;
  MyPrinter.BeginDoc;
    //page.PaintTo(myPrinter.Canvas, 0, 0);
    //myPrinter.Canvas.Draw(0,0, myBitMap);
    myPrinter.Canvas.CopyRect(Classes.Rect(0, 0, myPrinter.PaperSize.Width, myPrinter.PaperSize.Height),
       myBitMap.Canvas, Classes.Rect(0, 0, myBitMap.Width, myBitMap.Height));
  MyPrinter.EndDoc;
  myBitMap.Free;
end;

For this to work, do not use the Windows unit. The Windows unit has other definitions for Rect. What you see in the example is the following:

  • A bitmap is created and made the same size as the page control.
  • To avoid the border to print, the BorderStyle of the page is switched off before painting it to the bitmap and set back to its old value afterwards.
  • Then printing is started and the BitMap canvas content is copied to the printer canvas.

But notice one thing, in the process page is magnified. The Printer.papersize is considerably bigger than the the size of the bitmap, but the copy process fills the destination rectangle nicely. So, when we want to do this, we must make sure that the page dimensions have the same ratio as the paper dimension. You can figure out how to do it.

A problem with this way of working is of course that the pixels of the screen will show on the printed paper. As said, it is not ideal but it shows a principle. Controls do not have their own canvas; to print controls we first paint them on an object that does have its own canvas: the TBitMap. Now you know how it works, you can figure out a way to create fine artwork or documents. This will need objects that draw themselves properly in a TPanel with low resolution, but also on a TBitMap with high resolution. But, that is food for another article.

See also