artykuły

Delphi - Drukowanie

12:37
Tue, 9 November 2004
Tekst opisuje moduł Printers używany do drukowania. Wyjaśnia podstawowe zagadnienia dotyczące problemu przesyłania tekstu i grafiki na drukarkę, opisuje zagadnienia związane z rysowaniem po płótnie drukarki. Rozwiązuje problemy dotyczące wyśrodkowywania elementów wydruku.

Wstęp

Drukowanie? Tak, dzisiaj tym się właśnie zajmiemy. Temat drukowania nie jest rozległy gdy korzystamy ze standardowych modułów dołączonych razem zDelphi. Za ich pomocą możemy wydrukować dosłownie wszystko, więc nie ma potrzeby zagłębiać się w bezpośrednią obsługę drukarki.
Jednym z najważniejszych problemów jaki napotkamy będzie pozycjonowanie. Wiele niedoświadczonych programistów nie zwraca uwagi na pewien szczególny oraz istotny fakt. Drukarki mają różną rozdzielczość. Jest to pierwsza i najważniejsza rzecz na jaką chciałbym zwrócić Wam uwagę. Właśnie z tą własnością będziemy mieli najwięcej problemów, a co za tym idzie, ze skalowaniem stron na różne rozdzielczości. To dlatego sprawdzając swój program na innym sprzęcie, często otrzymywałeś nie do końca wynik, który chciałeś uzyskać. Na jednych brakowało części wydruku, na innych znów wydruk był zbyt mały. Co zrobić w takiej sytuacji? Mam zamiar praktycznie odpowiedzieć na to pytanie. Zapraszam!

Jak zacząć?

Delphiudostępnia nam moduł "Printers", który będzie nam potrzebny. Dodajmy go więc do listy używanych modułów - "uses". Następne co nas czeka to zadeklarowanie i utworzenie nowej klasy typuTPrinter. Zawiera ona takie właściwości jak szerokość oraz wysokość strony w pikselach (różna dla różnych rozdzielczości), płótno po którym będziemy rysować, oraz wiele innych użytecznych własności.
Wspomniałem o płótnie. To prawda - aby coś wydrukować, musimy to narysować na "płótnie" (od ang.Canvasznaczy płótno) drukarki, tak jak to robimy rysując po formularzu, czy innym obiekcie.Canvasjest "powierzchnią aktualnie drukowanej kartki". Zawiera ona opcję, które pozwalają nam narysować linię, koło, prostokąt i wiele innych figur.

Drukujemy pierwszy tekst

Zaczniemy od wydrukowania pewnego tekstu w lewym górnym rogu strony, czyli w punkcie (0,0). Nie potrzeba tutaj jakiś wymyślnych technik skalowania, ponieważ punkt (0,0) (jako jedyny) zawsze będzie na swoim miejscu i zawsze oznaczał będzie lewy, górny róg strony.

  1. UruchamiamyDelphi.
  2. Przechodzimy do "Edytora Kodu" i dodajemy modułPrintersdo listy używanych modułów "uses".
  3. Musimy teraz zadeklarować globalnie nową klasę jakoTPrinter. Aby to uczynić musimy dodać następującą linię do sekcji "var" znajdującej się przed (!) sekcjąimplementation: var Form1: TForm1; Drukarka: TPrinter;
  4. Zadeklarowaliśmy klasę, a jak wiadomo, klasy po deklaracji trzeba jeszcze utworzyć.
  5. Przechodzimy do "Widoku projektu" naciskając klawisz F12.
  6. Na formie układamy przycisk (paleta Standard) i klikamy nań dwukrotnie.Delphipomógł nam w tej chwili, automatycznie tworząc nową procedurę obsługującą zdarzenie kliknięcia na przycisk (czyli dla wtajemniczonych, obsługującą komunikatWM_LBUTTONCLICK).
  7. W nowo-utworzonej procedurze piszemy fragment kodu, który będzie odpowiedzialny za utworzenie nowej klasy: Drukarka := TPrinter.Create;
  8. Mamy teraz dostęp do możliwości drukowania. Aby coś wydrukować, musimy najpierw wydać komendęBeginDoc. Gdy ukończymy rysowanie na płótnie drukarki musimy powiadomić o tym system wydając komendęEndDoc. Dopiero wtedy system prześle stronę do druku. Spójrzcie: // Utworzenie klasy Drukarka := TPrinter.Create; // Rozpoczęcie drukowania Drukarka.BeginDoc; { tutaj rysujemy na Canvasie } // Zakończenie drukowania Drukarka.EndDoc;
  9. Do rysowania tekstu naCanvasieposłuży nam funkcjaTextOut(). Jej budowa przedstawia się następująco: procedure TextOut(X, Y: Integer; const Text: string); Pierwsze dwa parametry to pozycja tekstu (lewy górny róg), kolejny to tekst do narysowania.
  10. Spróbujemy teraz wydrukować tekst: // Utworzenie klasy Drukarka := TPrinter.Create; // Rozpoczęcie drukowania Drukarka.BeginDoc; // Narysowanie tekstu na Canvasie (płótnie) Drukarka.Canvas.TextOut(0, 0, 'Jakiś tam tekst'); // Zakończenie drukowania Drukarka.EndDoc;

Po udanym, jakże trudnym do wykonania drukowaniu tekstu ;) zapraszam do zapoznania się z innymi użytecznymi właściwościami klasyTPrinterorazTCanvas:

Metody klasy TPrinter
Metoda Opis
Abort Zakańcza drukowanie powodując utratę nie wydrukowanych informacji
BeginDoc Rozpoczyna zadanie drukowania
EndDoc Zakańcza zadanie drukowania wysyłając dane do drukarki
NewPage Rozpoczyna nową stronę (pamiętajmy, że Windows XP domyślnie drukuje "od końca")
Refresh Uaktualnia informacje o czcionkach i drukarkach.
 
Właściwości klasy TPrinter
Właściwość Opis
Aborted Przyjmuje wartość True (prawda) gdy użytkownik przerwał zadanie drukowania.
Copies Określa ilość kopii
Fonts Lista dostępnych czcionek dla danej drukarki
Orientation Umożliwia zmianę orientacji strony (pionowo lub poziomo).

poPortrait - pionowo (domyślnie)
poLandscape - poziomo
PageHeight Określa wysokość strony w pikselach dla aktualnie wybranej rozdzielczości.
PageWidth Określa szerokość strony w pikselach dla aktualnie wybranej rozdzielczości.
PageNumber Przechowuje numer aktualnie drukowanej strony.
PrinterIndex Umożliwia wybór drukarki (gdy przypiszesz tej właściwości wartość -1 to wybrana zostanie drukarka domyślna)
Printers Zwraca listę zainstalowanych w systemie drukarek.
Printing Określa, czy aktualnie coś jest drukowane
Title Określa tytuł dokumentu. Tytuł ten wyświetlany będzie w menager'ze drukarek.

Metody klasy TCanvas
Metoda Opis
TextOut Umożliwia narysowanie tekstu na Canvasie w określonej pozycji.
Draw Umożliwia wyświetlenie obrazka (bitmapy, grafiki) w określonej pozycji.
Ellipse Umożliwia narysowanie elipsy (w tym oczywiście również koła). Parametrami są lewy, górny oraz prawy, dolny "róg".
FillRect Rysuje prostokąt o wypełnieniu i stylu zgodnym ze stylem pędzla (Brush).
MoveTo()
LineTo()
Dwie procedury do narysowania linii. Za pomocą pierwszej ustawiamy pióro w danej pozycji, a za pomocą drugiej kreślimy od tego punktu określonej długości linię.
Lock Zabezpiecza płótno w sposób, aby inne wątki nie miały do niego dostępu. Przeznaczone dla aplikacji wielowątkowych.
Pie Rysuje wycinek koła. Narzędzie przydatne przy rysowaniu wykresów.
PolyBezier Rysuje linię Bézier'a (taką linię można płynnie wyginać).
Polygon Rysuje figurę o wierzchołkach podanych jako parametr.
Rectangle Rysuje prostokąt o wierzchołkach podanych jako parametr.
TextWidth Zwraca wielkość tekstu podanego jako parametr w poziomie (w pikselach).
TextHeight Zwraca wielkość tekstu podanego jako parametr w pionie (w pikselach).
Unlock Odblokowuje płótno (po jego wcześniejszym zablokowaniu przez procedurę Lock).
Refresh Odświerza płótno.

Drukujemy obrazek

Przejdźmy do rzeczy nieco trudniejszych niż drukowanie tekstu. Wydrukujmy obrazek. Co wy na to? Hmm... Myślę, że brzmi to interesująco. Potrzebny będzie nam tylko jakiś obrazek typu BMP. Spróbujmy więc.

  1. Uruchamiamy Delphi'ego.
  2. Naciśnięciem klawisza F12 przechodzimy do "Edytora kodu".
  3. Do listy "uses" dodajemy moduł "Printers".
  4. Do globalnej (tej przedimplementation) sekcji "var" dodajemy deklarację nowej klasy:Drukarka: TPrinter;
  5. Przechodzimy do widoku formularza (F12).
  6. Kładziemy na formularzu nowy przycisk.
  7. Klikamy nań dwukrotnie, przez co znów przechodzimy do "Edytora kodu", który czeka na nas z nowo-utworzoną procedurą.
  8. Uzupełniamy procedurę następująco: procedure TForm1.Button1Click(Sender: TObject); var obrazek : TBitmap; begin // Tworzymy nową klasę TBitmap obrazek := TBitmap.Create; // Ładujemy obrazek z pliku obrazek.LoadFromFile('C:\obrazek.bmp'); // Utworzenie klasy Drukarka := TPrinter.Create; // Rozpoczęcie drukowania Drukarka.BeginDoc; // Rysujemy obrazek na płótnie drukarki Drukarka.Canvas.Draw(0,0,obrazek); // Zmienna obrazek nie będzie już nam // potrzebna więc zwalniamy zajmowaną przez nią pamięć obrazek.Free; // Zakończenie drukowania Drukarka.EndDoc; end;

To już koniec. Tyle poleceń wystarczy aby wydrukować obrazek. Co zrobić aby był on na środku strony? Pomyślmy... Aby wypozycjonować obrazek w poziomie trzeba podzielić szerokość strony przez dwa i odjąć jeszcze połowę szerokości obrazka. Analogicznie należy postąpić z pozycją pionową:

Kolejne etapy pozycjonowania obrazka na stronie.
Teoria Wynik
Pozycjonowanie obrazka na stronie - etap pierwszy Pozycjonowanie obrazka na stronie - etap drugi
Pozycjonowanie obrazka na stronie - etap trzeci Pozycjonowanie obrazka na stronie - etap czwarty

Po połączeniu wyników naszej pracy otrzymujemy efekt końcowy

Pozycjonowanie obrazka na stronie - etap piąty (końcowy)
procedure TForm1.Button1Click(Sender: TObject); var obrazek : TBitmap; begin // Tworzymy nową klasę TBitmap obrazek := TBitmap.Create; // Ładujemy obrazek z pliku obrazek.LoadFromFile('C:\obrazek.bmp'); // Utworzenie klasy Drukarka := TPrinter.Create; // Rozpoczęcie drukowania Drukarka.BeginDoc; // Rysujemy obrazek na płótnie drukarki (wyśrodkowany) Drukarka.Canvas.Draw((Drukarka.PageWidth div 2)-(obrazek.Width div 2), (Drukarka.PageHeight div 2)-(obrazek.Height div 2), obrazek); // Zmienna obrazek nie będzie już nam // potrzebna więc zwalniamy zajmowaną przez nią pamięć obrazek.Free; // Zakończenie drukowania Drukarka.EndDoc; end;

Może nie jest to najpiękniejsze rozwiązanie problemu, ale ważne, że działa (przynajmniej u mnie ;)
Nasz wydrukowany obrazek jest jednak zbyt mały na wydruku. Co zrobić? Musimy go przeskalować! Najprostszą metodą jest napisanie takich instrukcji:

procedure TForm1.Button1Click(Sender: TObject); var Obrazek : TBitmap; ProporcjaX, ProporcjaY : integer; Obszar : TRect; NowaSzerokosc, NowaWysokosc : integer; begin // Tworzymy nowe klasy typu TBitmap Obrazek := TBitmap.Create; // Utworzenie nowej klasy TPrinter Drukarka := TPrinter.Create; // Ustawianie orientacji strony na poziomą Drukarka.Orientation := poLandscape; // Liczymy proporcję rozdzielczości monitora do rozdzielczości drukarki ProporcjaX := Drukarka.PageWidth div Screen.Width; ProporcjaY := Drukarka.PageHeight div Screen.Height; // Ładujemy obrazek z pliku Obrazek.LoadFromFile('C:\obrazek.bmp'); // Nowy obrazek będzie miał rozmiar proporcjonalnie większy do starego NowaSzerokosc := Obrazek.Width * ProporcjaX; NowaWysokosc := Obrazek.Height * ProporcjaY; // Stosujemy powiększenie obrazka zgodnie z obliczonymi proporcjami Obszar := Rect((Drukarka.PageWidth div 2)-(NowaSzerokosc div 2), (Drukarka.PageHeight div 2)-(NowaWysokosc div 2), (Drukarka.PageWidth div 2)+(NowaSzerokosc div 2), (Drukarka.PageHeight div 2)+(NowaWysokosc div 2)); // Rozpoczęcie drukowania Drukarka.BeginDoc; // Rysujemy odpowiednio powiększony obrazek na płótnie drukarki Drukarka.Canvas.StretchDraw(Obszar, Obrazek); // Zakończenie drukowania Drukarka.EndDoc; end;

Zwróćcie uwagę na linijkę zmieniającą orientację strony. Jest ona niezbędna do prawidłowego działania programu, gdyż zmienia orientację strony na taką, jaką mamy okazję obserwować na ekranie monitora (szerokość większa od wysokości).

Zakończenie

W przeciągu kilkunastu minut nauczyliście się obsługiwać drukarki. Pomyślcie co bylibyście w stanie zrobić przez minut czterdzieści! ;)
Do artykułu załączam kod źródłowy programu drukującego skalowane obrazki. Jest to typowy przykład dla tych którzy do tej pory nie uruchomili Delphiego ;)
Jednocześnie informuje, że zmienił się nieznacznie adres e-mail na który możecie pisać. Nowy adres e-mail macie poniżej.
Pozdrawiam!

12345
Delphi - Drukowanie Autor opinii: Czytelnicy, data przesłania: 5

Podobne artykuly:

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    Nie ma jeszcze żadnych komentarzy.
    Dexter