Tisk

Tiskový výstup v Delphi má dvě možnosti, textovou a grafickou. Protože naši studenti vystačí s vytištěním jedné grafické stránky (graf, tabulka s výsledky), budeme se věnovat pouze druhé možnosti.

Jako úplně první musíme mezi použité unit přidat unitu printers, například na konec seznamu:

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs, StdCtrls, Printers;

Tato akce je stejná i pro textový režim. Přidáním této unity nám přibude objekt printer, se kterým můžeme dále pracovat. V dalším textu se nebudu držet didaktického postupu, jen naznačím posloupnost kroků, které musí program provést, aby mohl vytisknout stránku.

Někdy se začíná volbou tiskárny. Vlastnosti tiskárny značně ovlivňují hodnoty, které musíme předávat tiskárně. Tiskárnu nejsnáze zvolíme tak, že vyvoláme dialog (komponentu z lišty "dialogs") PrintDialog pro výběr tiskárny:

  if printdialog1.execute then ;

PrintDialog1.Execute vrací true, pokud je stisknuto tlačítko OK, a false, pokud je stisknuto tlačítko Storno. Pokud se v druhém případě nemá nic vytisknout, je možné místo středníku napsat begin a end a mezi ně všechny ostatní příkazy pro tisk. Další možností je použít frázi

 if not printdialog1.execute then exit;

Zbytek procedury v tomto případě neproběhne (pozor na otevřené soubory a podobně).

V liště dialogů je ještě komponenta PrinterSetupDialog. Nebudeme ji asi potřebovat, protože vše podstatné je v dialogovém okně předchozí komponenty pod tlačítkem Vlastnosti (Properties). Výsledek nemusíme nikam přenášet. Unita Printers smí být v celém projektu použita jen jednou, takže k záměně nemůže dojít.

Zadávání dat pro grafický tisk zahájíme procedurou Printer.BeginDoc. Po sestavení grafické stánky ji do tiskové fronty Windows odešleme procedurou Printer.EndDoc. Pokud si to v průběhu práce rozmyslíme, můžeme zavolat proceduru Printer.Abort.

Poznámka - výše zmíněné dialogy lze samozřejmě volat jen před použitím Printer.BeginDoc. V průběhu samotného sestavování tiskové strany již nelze vlastnosti tiskárny měnit (až do Printer.EndDoc nebo Printer.Abort).

Pro tisk máme k dispozici plochu, která je dána rozlišením tiskárny. Je nám opět dostupná jako Canvas. Jeho parametry záleží na zvolené tiskárně a jejím nastavení (rozlišení, formát papíru a jiné). Následující program demonstruje rozlišení připojené tiskárny (volá nejprve dialog pro volbu tiskárny, protože jsem ověřoval rozlišení různých tiskáren). Program potřebuje zmíněnou komponentu z lišty Dialogs, tlačítko ke spuštění, a dva Labely:

  if PrintDialog1.Execute then begin
    Printer.BeginDoc;
    Label1.Caption := IntToStr(Printer.PageWidth);
    Label2.Caption := IntToStr(Printer.PageHeight);
    Printer.Abort;
  end;

Nebudeme nic tisknout, proto Abort. Zkuste si zobrazit rozlišení pro několik různých tiskáren, popřípadě pro jiný formát papíru (A4 na výšku, A4 na šířku).

Při tisku vytváříme obraz na (pomyslné) ploše, které opět říkáme Canvas. Voláme tedy stejné procedury, jako pro obrázek. Můžeme používat i stejné barvy - v průběhu zadávání dat jsou barvy překládány do těch, které zná tiskárna.

With

Abychom stále nepsali Printer.Canvas. (u složitějších programů možná dokonce unit4.Form4.Printer.Canvas. a podobně), lze použít direktivu pro překladač, kterou mu řekneme, že v následujících řádcích bude většina prvků z tohoto objektu (platí i pro třídy a záznamy). V Pascalu se tak učiní direktivou with ve tvaru

with <jméno objektu> do <příkaz>;

Pro jeden konkrétní příkaz použití with nedává smysl, proto se takřka bezvýhradně používá ve spojení s programovými závorkami begin - end (vyjímkou mohou být složité podmíněné příkazy, cykly a podobně). Například obdélník o rozměru 100x100 pixelů je možné vykreslit buď příkazy

  Printer.BeginDoc;
  Printer.Canvas.Pen.Width:=3;
  Printer.Canvas.Pen.Color:=clRed;
  Printer.Canvas.Rectangle(130,130,230,230);
  Printer.EndDoc;

nebo příkazy

  with Printer do begin
    BeginDoc;
    Canvas.Pen.Width:=3;
    Canvas.Pen.Color:=clRed;
    Canvas.Rectangle(130,130,230,230);
    EndDoc;
  end;

nebo příkazy

  Printer.BeginDoc;
  with Printer.Canvas do begin
    Pen.Width:=3;
    Pen.Color:=clRed;
    Rectangle(130,130,230,230);
  end;
  Printer.EndDoc;

Je na programátorovi, zda je pro něj vhodné tento postup použít. Je třeba si uvědomit, že každý objekt se pak bude hledat nejprve uvnitř deklarovaného objektu.

Pro tisk grafu vystačíme s příkazy MoveTo, LineTo, TextOut a nastavováním vlastností pera, jaké jsme si ukazovali minule. Nyní tedy již můžete napsat program, který nejprve namaluje graf zvolené funkce (sin(x), ...) na Canvas obrázku Image1, a pak tuto činnost zopakuje na Canvas tiskárny.

Poznámka: Zatímco Canvas obrázku a většiny jiných objektů lze číst bod po bodu, u tiskárny je propery "pixels" dostupná pouzde pro zápis, o čemž se můžeme přesvědčit, pokud hodnotu některého bodu změníme. Protože změna jednotlivého bodu by asi nemusela být vždy vidět, zkusme raději nadefinovat pomocnou proměnnou i a použít cyklus, například

for i:=1 to 1000 do pixels[150,i]:=clBlack;

Tiskárny v učebně jsou samozřejmě černobílé.


Poznámka. Také nám chybí návod, jak namalovat graf funkce. Co třeba takhle:

Mějme globální pole reálných čísel:

var
a : array[0..100] of real;

nejprve je něčím naplníme, například načtením do memo1.lines[...], nebo v cyklu požadovanou funkcí:

for i:=0 to 100 do
a[i]:=sin(i/100*pi*2);

pak určíme zvětšení, aby graf byl přes celý obrázek:

max:=-99999;
min:=99999;
for i:=0 to 100 do begin
if max<a[i] then max:=a[i];
if min>a[i] then min:=a[i];
end;
c:=(image1.height*0.9)/(max-min);

Z toho, že se zde vyskytl objekt image1, je patrné, že předpokládám, že se bude malovat do tohoto objektu. Je třeba jej vytvořit.

Vlastní vykreslení - nejprve se přenese kurzor na začátek, a pak se v cyklu vše pospojuje čarami:

image1.picture.canvas.pen.color:=clred;
image1.picture.canvas.moveto(10,
image1.height-10-round((a[0]-min)*c));
for i:=0 to 100 do 
image1.picture.canvas.lineto(10+i*3,
image1.height-10-round((a[0]-min)*c));

Místo *3 by mělo být vodorovné zvětšení. Takhle to bude rozumně pracovat pro šířky obrázků od cca 315 do cca 350. Navíc by se ještě měly namalovat černě osy.

Neověřeno!