Über mehrere Seiten drucken
Stehen wir vor der Aufgabe, ein größeres Schaubild, Diagramm o.ä. ausdrucken zu müssen, so müssen wir uns an die vorhin erwähnten API-Funktionen erinnern. Da ging es um Window und Viewport – und deren Ursprungskoordinaten lassen sich auch verschieben. Doch wie haben wir uns das vorzustellen?
Der große grüne Kasten in der Zeichnung stellt unsere virtuelle Leinwand dar, das Window. Die kleineren grauen Kästchen stehen für je ein DIN A 4-Blatt, also die Ausgabefläche, den Viewport. Würden wir unseren Ausdruck wie bisher an den Drucker schicken, würde dieser lediglich Seite 1 ausdrucken. Alles andere geht über den Papierrand hinaus und wird deshalb verschluckt. Denn standardmäßig steht der Koordinatenursprung (hier als dunkelgrünes Koordinatensystem in der linken oberen Ecke von Seite 3 eingezeichnet) an der linken oberen Ecke des Window, die identisch ist mit der linken oberen Ecke des Viewports.
Mit Hilfe der Win32-API-Funktion SetWindowOrgEx lässt sich der Koordinatenursprung auf unserer Leinwand verschieben. Verschieben wir ihn z.B. um zwei Seitenbreiten nach rechts, wird alles gedruckt, was der Fläche eines Viewports (sprich eines Blattes) entspricht und an dieser Stelle beginnt. Die Koordinaten unserer Leinwand müssen dafür nicht umgerechnet werden. Selbst wenn wir hier beispielsweise bei einem x-Wert von 500 mm sind, wird das automatisch auf die Viewport-Koordinaten umgerechnet.
Nun ist das Drucken über mehrere Seiten kein Hexenwerk mehr: Wir stellen uns den Ausdruck wie in obiger Abbildung als Tabelle vor und legen einfach zwei Schleifen über unsere Leinwand – eine über die „Zeilen“, die jeweils einer Papierhöhe entsprechen, und innerhalb der Zeilen nochmal eine über die „Spalten“, also die Papierbreite. Entsprechend verschieben wir den Koordinatenursprung unseres Window. Hier das Gerüst dazu:
procedure DruckenUeberMehrereSeiten; var seitenbreite, seitenhoehe, offsetX, offsetY: integer; mmpropixelx, mmpropixely: real; komplettebreite, komplettehoehe, seitenX, seitenY: integer; x,y, leftoffset, topoffset: integer; begin if PrintDialog1.Execute then begin printer.Orientation:=poLandscape; //Drucken im Querformat printer.BeginDoc; printer.Title:='Mein Ausdruck'; //Titel, der im Druckmanager angezeigt wird SetMapMode(printer.Canvas.Handle, MM_LOMETRIC); // 1/10 mm //Druckerauflösung (mm pro Pixel) ermitteln mmpropixelx:=25.4/GetDeviceCaps(printer.handle, LOGPIXELSY); mmpropixely:=25.4/GetDeviceCaps(printer.handle, LOGPIXELSY); //Papiergröße ermitteln seitenbreite:=round(GetDeviceCaps(printer.handle, PHYSICALWIDTH)* MMProPixelX); seitenhoehe:=round(GetDeviceCaps(printer.handle, PHYSICALHEIGHT)* MMPropixelY); //nicht bedruckbare Seitenränder ermitteln offsetX:=round(GetDeviceCaps(printer.handle, PHYSICALOFFSETX)*MMProPixelX); offsetY:=round(GetDeviceCaps(printer.handle, PHYSICALOFFSETY)*MMpropixelY); topoffset:=0; //Größe unseres gesamten Ausdrucks komplettebreite:=gesamtX; komplettehoehe:=gesamtY; //Anzahl der "Zeilen" (seitenY) und "Spalten" (seitenX) seitenX:=ceil(kompletteBreite/((Seitenbreite-2*OffsetX)*10)); seitenY:=ceil(kompletteHoehe/((Seitenhoehe-2*OffsetY)*10)); //Schleife über die "Zeilen" for y:=1 to SeitenY do begin leftoffset:=0; //Schleife über die "Spalten" for x:=1 to SeitenX do begin //Verschieben des Koordinatenursprungs SetWindowOrgEx(printer.Handle,LeftOffset,TopOffset,nil); //hier normale Druck-Methode aufrufen //für nächste "Spalte" Abstand vom linken Rand um eine //Blattbreite nach rechts verschieben leftoffset:=leftoffset+(Seitenbreite-2*OffsetX)*10; if x<SeitenX then begin printer.NewPage; SetMapMode(printer.Canvas.Handle, MM_LOMETRIC); end; end; if y<SeitenY then begin printer.NewPage; SetMapMode(printer.Canvas.Handle, MM_LOMETRIC); end; //für nächste "Zeile" Abstand vom oberen Rand um eine //Blatthöhe nach unten verschieben topoffset:=topoffset-(Seitenhoehe-2*OffsetY)*10; end; printer.EndDoc; end; end;
Der Aufruf von SetMapMode nach Printer.NewPage ist nur unter Windows 9x/Me nötig. Unter NT/2000/XP werden die Seitenattribute dagegen durch eine neue Seite nicht zurückgesetzt. Der SetMapMode-Aufruf wäre hier also nicht nötig, schadet aber auch nicht.