Autor Beitrag
Backslash
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 202

WIN XP
Delphi 5 Ent, Delphi 2005 Prof
BeitragVerfasst: Di 27.03.07 01:21 
Ich möchte hier ein Tutorial zum Drucken mit der TPrinter-Klasse veröffentlichen. In den letzten Wochen und Monaten habe ich mehrmals Fragen zum Drucken gesehen. Bei Fragen oder Hinweisen werde ich diese sehr gern in das Tutorial aufnehmen. Für Erstellen einer Seitenvorschau folgt noch ein zweites Tutorial.

Lange Rede kurzer Sinn, viel Spaß beim Lesen

Gruß

Backslash

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

Inhalt des Tutorials:
- Erstellung von Druckaufträgen
- Das Bedrucken von Seiten
- Wählen des Druckers durch den Anwender
- Textverkürzung (Maximalbreite des Textes)

... weitere Inhalte folgen in den nächsten Tagen

Was das Tutorial nicht beinhaltet:
- Eine Vorschaufunktion zur Seitenvorschau
- Die Berechnung der Seitenanzahl des Druckauftrags
- ... folglich das Auswählen (Seite 1 - x) zum Drucken

-> das folgt in den nächsten Tagen im zweiten Tutorial "Drucken mit TPrinter II".

Was ist TPrinter?

TPrinter ist eine Klasse, die als Schnittstelle zwischen einer Delphi-Anwendung und dem Drucker fungiert. Sie bietet die Möglichkeit in wenigen Schritten auf dem Drucker Text oder Grafiken, sowie Rahmen, etc. zu drucken. TPrinter is weit umfangreicher als man auf den ersten Blick glauben mag. Einige Denkanstöße was man damit alles machen kann, folgen im Tutorial.

1. Zugriff auf die Druckschnittstelle beschaffen

Wie jede Klasse befindet sich TPrinter ebenfalls in einer Unit. Diese muss in das Projekt eingebunden werden. Das geschieht über den Uses-Abschnitt in der Anwendung.

ausblenden Delphi-Quelltext
1:
2:
3:
uses
  //[...]
  Printers;


2. Druckaufträge starten und verwalten

Wir haben nun Zugriff auf die Printer-Schnittstelle. Druckaufträge können direkt aus der Anwendung heraus schnell erstellt und verwaltet werden.

:idea: Hinweis: Der Titel des Druckauftrags kann vorab über "Printer.Title" festgelegt werden.
Beispiel: Printer.Title := 'Druckauftrag 1';

Druckauftrag starten:
Befehl: Printer.BeginDoc;

- Der Befehl startet einen Druckauftrag, (nicht eine neue Seite!)

Neue Seite erstellen:
Befehl: Printer.NewPage;

- Dieser Befehl erstellt eine neue Seite und gibt die Möglichkeit auf ihr zu drucken. Der Befehl kann beliebig oft zwischen Printer.BeginDoc; und Printer.EndDoc; aufgerufen werden. Für jeden Aufruf wird später eine neue Seite gedruckt.

Druckauftrag beenden:
Befehl: Printer.EndDoc;

3. Auflösung des Druckers - DPI

Da ein Drucker mit "Dots per Inch", sprich DPI arbeitet und das gleichzeitig die Auflösung angibt kann das Ergebnis von Drucker zu Drucker unterschiedlich sein. Also sollte man in Erfahrung bringen, wieviele Pixel man pro Seite bedrucken kann. Dabei ist es völlig egal, ob man nun auf DINA3, DINA4, etc. druckt. Es verändert sich lediglich der bedruckbare Bereich.

maximale Seitenhöhe in Pixel
Zugriff über: "Printer.PageHeight"

maximale Seitenbreite in Pixel
Zugriff über: "Printer.PageWidth"

Printer.Pageheight und Printer.Pagewidth variieren je Drucker und verwendetem DIN-Format. Daher macht es unter Umständen Sinn bei Breitenangaben auf dem Dokument mit Prozentangaben zu arbeiten. Man springs beispielsweise um 30% der maximal möglichen Pixel nach rechts und setzt deinen Text da hin.

Das sieht in der Praxis folgendermaßen aus

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
const
  Percentage = 30// die xPosition soll 30 % der Dokumentbreite betragen
var
  xPos : Integer;  // die zu berechnende x-Position
begin
  xPos := Trunc((Printer.PageWidth / 100) * 30);
end;


:idea: Hinweis:

Der Befehl Trunc schneidet die Nachkommastellen ab und wird zwecks Genauigkeit erst nach der Berechnung der xPosition
ausgefüht.

Mit diesem Wissen lässt sich nun auch auf unterschiedlichen DIN-Größen Text an der verhältnismäßig gleichen Position auf dem Dokument ausgeben. Das kann sehr hilfreich sein um komplexe Tabellen auf unterschiedlichen Systemen ausdrucken zu lassen.

3. Bedrucken einer Seite über TCanvas

Wir kennen jetzt die Grundlagen, wie man Druckaufträge erstellt und wissen was es mit der Auflösung DPI auf sich hat und wie wir anhand der Seitenbreite Textpositionen berechnen.

TCanvas

Was ist TCanvas? "Canvas" bedeutet wörtlich übersetzt "Leinwand". TCanvas ist eine nützliche Komponente, die in vielen anderen Delphi-Komponenten wie beispielsweise in TImage vorhanden ist. Auch die Druckerschnittstelle TPrinter besitzt einen Canvas.

Mit TCanvas lassen sich Text oder auch Rahmen, Elipsen, einzelne Pixel, schöne Verzierungen etc. auf deinem Dokument zeichnen. Die Delphi Hilfe nähere Auskunft zu "TCanvas". Die Werte Printer.PageWidth und Printer.PageHeight helfen dabei im "Rahmen" des Dokuments zu bleiben.

Ansteuerung von Canvas: "Printer.Canvas"

Textausgabe auf dem Drucker:

Canvas verfügt über eine Methode "Textout", die Text auf einer bestimmten Position der aktuellen Seite ausgibt.

:idea: Zur Erinnerung: Eine aktuelle Seite wurde vorher mit "Printer.NewPage" erstellt.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
  //[...]
  Printer.Canvas.TextOut(1020'test');


Mit diesem Befehl gibst man beispielsweise ganz weit oben links auf der aktuellen Seite einen Text aus. Die ersten beiden Attribute geben die x- und y-Position an. Wichtig: Die x- und y-Werte beginnen oben links am Dokument. Erhöhst man beispielsweise y bei der Textausgabe, wird der Text weiter unten gezeichnet.

4. Arbeiten mit Schriftattributen


Möchte man die Schriftattribute ändern geht das mit dem "Printer.Canvas.Font" Objekt. TFont befindet sich auch in anderen Delphi-Komponenten wie beispielsweise "TLabel". Im Objektinspektor kann man schön die Eigenschaften sehen die TFont bietet. Alternativ hilft auch hier wieder ein geziehltes Suchen nach "TFont" in der Delphi-Hilfe.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
Printer.Canvas.Font.Size := 12// Schriftgröße 12
Printer.Canvas.Font.Name := 'Verdana'// Schriftart Verdana


Textbreite und Texthöhe

Wird der Text zu hoch oder zu lang ausgegeben, kann man das mit "Printer.Canvas.TextWidth" oder "Printer.Canvas.TextWeight" prüfen. Diesen beiden Funktionen geben die Anzahl der benötigten Pixel auf dem aktuellen Dokument zurück, die das Zeichnen eines Textes sowohl in Breite als auch in Höhe benötigen würde.

:idea: Hinweis: Damit lassen sich nützliche Sachen bewerkstelligen. Man kann a. beispielsweise den Text abschneiden und ein "..." anfügen, wenn er zu groß wird. Oder man fügt b. einen Zeilenumbruch an der entsprechenden Stelle ein.

Text auf Textbreite zurechtschneiden

Für den Fall a. habe ich eine kleine aber feine Funktion geschrieben. Ich bin sicher die gibt es schon in ähnlicher Form in Delphi aber ich füg sie trotzdem mal ins Tutorial ein. Dieser Funktion übergibt man als Parameter 1. den Text, 2. die Maximalbreite des Textes und 3. den Printer.Canvas. Die Funktion schneidet dann den überflüssigen Rest ab und ändert die letzten vier Zeichen in " ...". Die Archivierungssoftware Winzip setzt mit hoher Wahrscheinlichkeit einen Befehl mit identischer Wirkweise zum Drucken von Dateilisten von Archiven ein.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
// Einen String verkürzen und " ..." ans Ende anfügen
function ShortenStr(const Str : string;
                    Canvas : TCanvas;
                    MaxWidth : Integer) : string;
var
  i : Integer;
  S : string;
  SLength : Integer;
begin
  S := Str;
  SLength := Length(S);
  while Canvas.TextWidth(S) > MaxWidth do
  begin
    dec(SLength, 1);
    SetLength(S, SLength);
  end;
  Result := S;
  if Length(S) = length(Str) then exit;
  if length(S) >= 4 then
  begin
    for i := Length(S) downto Length(S) - 2 do
      Result[i] := '.';
    Result[Length(S) - 3] := ' ';
  end;
end;


:idea: Hinweis: Um aber nicht für jede Zeile die Texthöhe über eine Funktion berechnen zu lassen, gibt es auch einen einfacheren Weg:

"Printer.Canvas.Font.Height" gibt die Pixel-Höhe der Schrift auf der gerade zu bedruckenden Seite aus. Ändert man die Schriftart, ändert sich auch die Höhe "Font.Height". ACHTUNG: Font.Height ist nicht gleich Font.Size. Height gibt die Höhe von Pixeln zurück, Size die entsprechende Schriftgröße.

Wie mir aufgefallen ist, ist Font.Height bei mir ein Wert mit negativem Vorzeichen. Man sollte hier also stets den Betrag nehmen, wenn man die Y-Position beim Einfügen einer neuen Zeile um Printer.Canvas.Font.Height erhöht.


5. Arbeiten mit Druckdialogen

Da es oft gewollt ist dem Anwender die Möglichkeit zu geben unmittelbar vor dem Drucken einen Drucker zu wählen, erklär ich hier wie es geht: Im der Abschnitt "Dialoge" der Delphi Komponenten findet man den "PrintDialog". Zieht man diesen auf das Formular, hat man nun die Möglichkeit den Drucker, sowie weitere Parameter zu ändern

Aufrufbeispiel
ausblenden Delphi-Quelltext
1:
2:
3:
4:
if PrintDialog.Execute then
begin
  DoPrint; // das sei selbstgeschriebene Prozedur zum Drucken, in der ein Druckauftrag erstellt und der Inhalt gedruckt wird
end;


Die Zeile "if PrintDialog.Execute" ruft den Druckdialog auf und gibt sofern der Benutzer nicht Abbrechen gewählt hat ein "True" zurück.

:idea: Hinweis: Hat man diesen Dialog aufgerufen, muss man den Drucker im nun folgenden Druckauftrag nicht mehr von Hand setzen. Der Aufruf genügt. Den Rest erledigt der Dialog intern.

In dem Dialog kann man auch die zu druckenden Seiten anzeigen. Diese müssen aber selbst berechnet werden. Wie das geht, zeige ich im zweiten Tutorial mit der Vorschaufunktion. Dafür gibt es mehrere Herangehensweisen.

Druckersetup

Kleiner Hinweis am Rande: Im Abschnitt "Dialoge" befindet sich auch ein "PrinterSetupDialog". Damit kann man das normale Druckersetup aufrufen und so relativ schnell in seine Anwendung implementieren.

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

Ende des Tutorials

Fragen und Kritik könnt ihr mir per PN senden. Ich werde auf Wunsch gern Verbesserungen und Erweiterungen vornehmen. Das Tutorial stellt keineswegs ein Rundum-Wohlfühlpaket zur Verfügung. Hier werden nur die Grundlagen genannt, damit man sich schnell in TPrinter einarbeiten kann.
Backslash Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 202

WIN XP
Delphi 5 Ent, Delphi 2005 Prof
BeitragVerfasst: Di 27.03.07 18:15 
TODO-Liste fürs Tutorial:

- Druckerliste auslesen
- Drucker von Hand setzen