Using the printer/de

From Free Pascal wiki
Jump to: navigation, search

Deutsch (de) English (en) español (es) 日本語 (ja)

Zurück zu den Zusätzlichen Informationen.


Einführung

Drucken ist einfach in Lazarus/FreePascal. Dennoch sollten Sie einige erforderliche Schritte beachten. Wir fangen mit den ersten einfachen Schritten an. Anschließend können Sie dem Weg zu gehobenen Drucktechniken folgen. Dieser Artikel beschreibt die dazu erforderlichen Schritte, die von verschiedenen Forumsseiten und Beispielen zusammengetragen wurden. Nach den grundlegenden Schritten werden wir etwas Text ausdrucken. Zuletzt gibt es noch einen Tipp für das etwas fortgeschrittenere Ausdrucken.

Die grundlegenden Schritte

Um Drucker zu benutzen, müssen Sie Folgendes beachten:

  1. Fügen Sie das Printer4Lazarus - Package zu Ihren Projektanforderungen hinzu.
  2. Fügen Sie die Printers - Unit zum uses-Abschnitt Ihrer Unit hinzu.
  3. Verwenden Sie das existierende Printer - Objekt.

Fügen Sie das Printer4Lazarus - Package zu Ihren Projektanforderungen hinzu

Das Printer4Lazarus - Package legt einen Drucker als Grundlage fest und bietet somit plattformunabhängiges Ausdrucken. Deshalb kann folgendes Verfahren auf verschiedenen Plattformen eingesetzt werden.

Führen Sie in der Lazarus IDE folgende Schritte durch:

  1. Klicken Sie im Menü Projekt auf Projektinspektor .... Es wird ein Fenster mit einer Baumstruktur angezeigt. Einer der Zweige lautet Benötigte Packages. Als Standard wird von Benötigte Packages das LCL - Package angezeigt.
  2. Klicken Sie die Schaltfläche Hinzufügen, den Knopf mit dem Pluszeichen am oberen Fensterrand.
  3. Öffnen Sie die Seite Neue Anforderung.
  4. Aus dem Listenfeld Package-Name wählen Sie Printer4Lazarus aus.
  5. Klicken Sie auf Neue Abhängigkeit erzeugen.
  6. Printer4Lazarus wird jetzt im Zweig Benötigte Packages angezeigt.

Fügen Sie die Printers - Unit zum uses-Abschnitt Ihrer Unit hinzu

Dieser Schritt ist einfach und das Ergebnis sollte so ähnlich aussehen:

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

Verwenden Sie das existierende Printer - Objekt

Nehmen wir an, Sie wollen zum Ausdrucken eines Textes eine Schaltfläche verwenden. Legen Sie auf Ihr Form eine Schaltfläche namens PrintBtn und bearbeiten Sie das OnClick-Ereignis zu Folgendem:

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;

Habe ich grundlegend und einfach geschrieben? Das obige Beispiel ist schon irgendwie komplex. Neben der reinen Textausgabe stellt es auch ein Beispiel dar, wie Sie den Text formatieren können.

Von begin bis zum end; geschieht Folgendes:

  • Mit Printer.BeginDoc starten Sie das Drucken - trotzdem wird noch nichts zum Drucker gesendet bis Sie mit Printer.EndDoc; abschließen.
  • Das Druckerobjekt benutzt eine Leinwand Canvas auf die die Ausgabe gezeichnet wird. Diese Zeichnung landet zuletzt auf der gedruckten Seite. Canvas.Font ist das Fontobjekt der Ausgabeleinwand. Der nachfolgende Aufruf von TextOut nimmt zur Textausgabe die jetzt getroffenen Einstellungen des Fontobjektes.
  • Alles, was Sie auf die Leinwand zeichnen, muss mittels Koordinaten positioniert werden. Also, berechnen wir eine Zeilenhöhe LineHeight zum vertikalen Positionieren. Sie könnte das auch für die horizontale Position machen, ich hab es hier aber bei der Einstellung LEFTMARGIN belassen.
  • Jetz wird der Text mit dem Aufruf TextOut gezeichnet.
  • Das überwältigende Ergebnis wird mittels Printer.EndDoc an den Drucker geschickt.

In einigen Foren wird behauptet, dass PrintDialog (der Druckerauswahl-Dialog) für ein gutes Funktionien nötig ist. Ich konnte das nicht (mehr) nachvollziehen.

Die nächsten Schritte

Nach diesen grundlegenden Schritten könnten Sie als weitere Schritte Folgendes ausprobieren:

  • Machen Sie auf dem Papier Zeichnungen.
  • Formatieren Sie den Text ansprechender.
  • Wählen Sie einen anderen Drucker und vergleichen Sie die Ergebnisse.

In der Lazarus-Distribution gibt es ein Beipielsprojekt, das den Drucker im Raw - Modus ansteuert. Sie finden dieses Beispiel im Ordner $(lazarusdir)\components\printers\samples\rawmode\rawmodetest.lpi. Ein weiteres Beispiel erläutert die Auswahl eines Druckers: $(lazarusdir)\components\printers\samples\dialogs\selectprinter.lpi.

Gehobene Schritte: Drucksteuerung

Das Druckerobjekt ermöglicht primär das Zeichnen auf eine Leinwand und das Senden dieses Bildes an den Drucker. Wenn wir auf diesem oben gezeigten Weg weiter gingen, würden wir die Methoden der Druckerleinwand zum Zeichnen von Text, Ellipsen, Kästchen u.s.w. einsetzen.

Für einen ernsthaften Programmierer ist dies wenig ansprechend. Sie arbeiten an einem besseren CAD-Programm oder einer weiteren Bilderverwaltung und möchten einen Ausdruck von Ihrem Programm an Ihren Drucker senden? Der Versuch, das perfekte Bild in Methodenaufrufe der Leinwand umzusetzen, ist nicht der Weg: Sie haben das Bild nämlich schon.

Jedes einzelne Steuerelement das auf einem Form liegt, liefert auch ein Bild auf einem TCanvas - Objekt genau wie beim Drucken. Dies nutzen wir aus, um das Bild vom Bildschirm zum Drucker zu bringen.

Angenommen Sie erstellen ein Vorschaubild. Sie erzeugen ein Form und darauf legen Sie ein TPanel ab. Dieses Panel hat einen leicht grauen Hintergrund für die Vorschau. Auf das Panel legen Sie ein weiteres TPanel - Objekt namens Seite (page). Diese Seite wird weiß und stellt das Papier dar. Sie können leicht die Größe der Seite anpassen.

Auf diese Seite geben wir ein TShape - Objekt, bspw. ein nettes rotes, abgerundetes Rechteck. Versuchen Sie jetzt Folgendes in der Ereignismethode PrintBtnClick:

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

Was passiert:

  • BeginDoc startet die Druckaufbereitung (aber es wird noch nichts gesendet).
  • page.PaintTo schickt die Ausgaben unseres TPanel - Objekts an die Druckerleinwand. Beachten Sie:
    1. Sie können die Methode PaintTo jedes beliebigen Steuerelements aus der Hierachie verwenden. Sie könnten ebenso die Ausgabe des ganzen Fensters an den Drucker senden.
    2. Jedes Steuerelement mit einer PaintTo - Methode bietet sich an, also seien Sie kreativ. Für die Ausgabe Ihrer Bildverwaltung eignet sich ein TImage.
    3. TCanvas besitzt auch eine Methode zum Kopieren rechteckiger Bereiche zu einer anderen Leinwand. Allerdings klappt das nur, wenn ein Objekt wirklich auf eine Leinwand zeichnet. Viele Steuerelemente greifen aber über Container auf eine Leinwand zu, dann geht das Kopieren nicht. Zumindest hat es bei mir nicht funktioniert.
    4. Versichern Sie sich, dass das SteuerelementMake sichtbar ist. Unsichtbare Elemente werden nicht gezeichnet, nicht einmal zum Drucker.
  • EndDoc sendet die Zeichnung zum Drucker.

Und weiter geht's: Änderung der Größe

Der Drucker hat eine wesentlich höhere Auflösung (Pixel pro Zoll) als ein Bildschirm. Deshalb resultiert die vom Bildschirm zum Drucker umgeleitete Ausgabe als ziemlich winziger Ausdruck auf dem Papier. Für eine gut aussehende Ausgabe sind darum Skalierung und Layoutkontrolle wichtig. Es wäre toll, wenn man eine exakt gleich große Kopie des Bildschirms ach auf Papier haben könnte.

Kümmern wir uns im Augenblick nicht um dieses Ideal, eher um die Idee dahinter. Wie bereits erwähnt, haben Steuerelemente keine eigene Leinwand, sondern verlassen sich auf die Leinwand eines Containers oder ihres Owners. Allerdings haben manche Komponenten auch ihre eigene Leinwand. Ich wähle TBitMap und dort klappt es wie folgt.

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;

Damit das funktioniert dürfen Sie nicht die Unit Windows verwenden. Die Windows - Unit hat andere Definitionen für Rect. Was Sie im Beispiel sehen, ist dies:

  • Eine Bitmap wird erzeugt mit gleicher Größe wie beim Page-Steuerelement.
  • Sie vermeiden den Ausdruck des Randes, indem Sie die Eigenschaft BorderStyle der Seite vor dem Drucken zur Bitmap abschalten und hinterher auf die alten Werte zurücksetzen.
  • Das Drucken wird gestartet und der Leinwandinhalt der BitMap wir auf die Druckerleinwand kopiert.

Aber beachten Sie, dass die Seite page in diesem Vorgang vergrößert wird. Die Papiergröße Printer.papersize ist erheblich größer als die Bitmap, aber der Kopiervorgang füllt das Zielrechteck gut aus. Um das zu erreichen, müssen wir sicherstellen, dass die Dimensionen von page und die des Papiers das selbe Verhältnis aufweisen. Sie sehen sicher, wie das geschieht.

Ein Problem dabei ist, dass der Ausdruck auf dem Papier "pixelig" wirkt. Wie gesagt, es ist nicht ideal, aber es zeigt das Prinzip. Steuerelemente haben keine eigene Leinwand; um sie auszudrucken zeichnen wir sie zuerst auf ein Objekt mit eigener Leinwand: eine TBitMap. Da Sie jetzt also wissen, wie das geht, können Sie einen Weg herausfinden, um richtige Kunstwerke oder Dokumente herzustellen. Dazu brauchen Sie Objekte, die sich selbst in ein TPanel mit niederer Auflösung, aber auch in ein TBitMap mit hoher Auflösung zeichnen können. Aber das ist schon Stoff für einen weiteren Artikel.


Übersetzt von: --billyraybones 20:10, 21 September 2013 (CEST)