Drukowanie Memo

Adam Boduch

Komponent "Memo" nie posiada odpowiedniej procedury drukowania tekstu tak jak to jest w przypadku komponentu "RichEdit" - trzeba takową napisać.

Przy pisaniu procedury drukującej trzeba wsiąść pod uwagę wiele czynników m.in. ile linii zmieści się na jednej stronie, wysokość linii, odstępy między liniami.

Nie będę tutaj opisywał samego procesu drukowania - o tym możecie poczytać w artykule "Drukowanie".

Na samym początku należy obrać jednostkę miary. W naszym przypadku będzie to piksel. Należy jeszcze przeliczyć ilość
pikseli na jeden cal. Umożliwia to polecenie "GetDeciveCaps":

// liczba pikseli w poziomie
GetDeviceCaps(Printer.Handle, LOGPIXELSX);  

// liczba pikseli w pionie
GetDeviceCaps(Printer.Handle, LOGPIXELSY); 

Na tej podstawie można już obliczyć wysokość jednej linii:

{ Przypisz do drukarki czcionke uzywana przez komponent typu TMemo" }
  Printer.Canvas.Font := memText.Font;

{
  Tutaj nastepuje obliczenie wysokosci linii na podst. wielkosci czcionki uzywanej przez komponent "memo". Funkcja "MulDiv" wyznacza wysokosc linii, a polecenie "GetDeviceCaps" oblicza liczbe pikseli na cal ekranu  ( LOGPIXELSY ). Wszystko to musi byc opatrzone slowem "Abs", ktore powoduje przeksztalcenie liczby ujemnej na dodatnia jezzeli nachodzi taka potrzeba.
}
  LineHeight := Abs(MulDiv(Printer.Canvas.Font.Size, 
   GetDeviceCaps(Printer.Handle, LOGPIXELSY), 70));

To już mamy. Trzeba teraz sprawdzić ile linii zmieści się na jednej stronie:

  LineCount := (Printer.PageHeight div LineHeight) - 5;

Liczbę linii przypadających na jedną stronę obliczana jest na podst. wysokości strony. Ta wartość zostanie dzielona przez wysokość linii co daje liczbę mogących się znaleźć na jednej stronie linijek. Od tej wartości odejmowana jest cyfra 5, żeby zostawić miejsce na dolny nagłówek.

To nie jest jednak wszystko co związane jest z obliczaniem różnych
wartości. Trzeba bowiem obliczyć przerwę między kolejnymi liniami.
Ja przyjąłem wartość 30% z wielkości linii. Oto kod:


{
  Tutaj natomias oblicznaa jest wilekosc odstepu pomiedzy     poszczegolnymi liniami. Wielkosc lini mnozona jest przez 3, a nastepnie wartosc ta dzielona jest przez 0 co w rezultadzie daje odstep w   wysokosci 30%
}
  Inc(LineHeight, (LineHeight * 3) div 10);

Ufff. Zacznijmy drukować :) Ja zrobiłem tak, aby można było na
samej górze strony umieszczać nagłówek. Ponieważ wyśrodkowanie
tekstu w poziomie umożliwia funkcja "DrawText" trzeba się
trochę pobawić. Funkcja ta wymaga podania prostokąta wobec którego
tekst zostanie wyśrodkowany. Trzeba w tym celu zadeklarować
zmienną typu "TRect".

{
  Nastepuje tutaj oblicznie wielkosci naglowka. Zmienna "R" zawiera teraz  kwadrat wewnatrz ktorego rysowany bedzie tekst. Kwadrat ten bedzie mial  wysokosc dwoch linii tekstu.
}
  with R do
  begin
    Top := LineHeight;
    Left := 20;
    Right := Printer.PageWidth; // szerokość strony
    Bottom := LineHeight * 2;
  end;

{ Wyswietl wycentrowany tekst mieszczacy sie w kwadracie "R". }
  DrawText(Printer.Handle, 
 'Service for programmers [http://www.programowanie.of.pl]',-1, R, DT_CENTER);

Nagłówek już mamy. Jest OK. Może teraz wydaje Ci się to niejasne, ale poniżej przedstawiam cały listing i mam nadzieje, że wiele rzeczy się wówczas wyjaśni.

(****************************************************************)
(*                                                              *)
(*      Example - programme printing text for Delphi 5          *)
(*      Copyright (c) 2001 by Service for programmers           *)
(*              Adam Boduch - Build: 17.03.2001                 *)
(*            HTTP://WWW.PROGRAMOWANIE.OF.PL                    *)
(*              E - mail:  boduch@poland.com                    *)
(*                                                              *)
(****************************************************************)

unit MainFrm;

interface

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

type
  TMainForm = class(TForm)
    memText: TMemo;
    btnPrint: TButton;
    procedure btnPrintClick(Sender: TObject);
  private
    procedure PrintText(PText : TStrings; lMargin : Integer = 20);
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

uses Printers; { <-- modul umozliwiajacy operaje drukowania }

{$R *.DFM}

procedure TMainForm.PrintText(PText: TStrings; lMargin : Integer);
var
  S : String;
  I : Integer;
  R : TRect;
  LineCount : Integer; // ilosc linii mogacych zmiescic sie na jednej stronie
  LineHeight : Integer; // wysokosc jednej linii na podst. wielkosci czcionki
  Line : Integer; // aktualnie drukowana linia
begin
{ Przypisz do drukarki czcionke uzywana przez komponent typu "TMemo" }
  Printer.Canvas.Font := memText.Font;

{
  Tutaj nastepuje obliczenie wysokosci linii na podst. wielkosci czcionki  uzywanej rzez komponent "memo". Funkcja "MulDiv" wyznacza wysokosc linii,  a polecenie "GetDeviceCaps" oblicza liczbe pikseli na cal ekranu  ( LOGPIXELSY ). Wszystko to musi byc opatrzone slowem "Abs", ktore   powoduje przeksztalcenie liczby ujemnej na dodatnia jezzeli nachodzi  taka potrzeba.
}
  LineHeight := Abs(MulDiv(Printer.Canvas.Font.Size, 
  GetDeviceCaps(Printer.Handle, LOGPIXELSY), 70));

{
  Tutaj natomias oblicznaa jest wilekosc odstepu pomiedzy poszczegolnymi  liniami. Wielkosc lini mnozona jest przez 3, a nastepnie wartosc ta dzielona jest przez 10 co w rezultadzie daje odstep w wysokosci 30%
}
  Inc(LineHeight, (LineHeight * 3) div 10);

{
  Okreslenie ilosci linii mogacych sie znalezc na jednej stronie. Wartosc ta obliczana na podst. wysokosci strony, ktora to wielkosc zostanie dzielona przez wielkosc linii, a nastepnie od tej wartosci odejmowana jest cyfra 5, aby zostawic miejsce na dolny margines.
}
  LineCount := (Printer.PageHeight div LineHeight) - 5;

  Line := 5; // rozpocznij drukowanie w piatej linijce
  Printer.BeginDoc; // rozpocznij drukowanie

{
  Nastepuje tutaj oblicznie wielkosci naglowka. Zmienna "R" zawiera teraz kwadrat wewnatrz ktorego rysowany bedzie tekst. Kwadrat ten bedzie mial  wysokosc dwoch linii tekstu.
}
  with R do
  begin
    Top := LineHeight;
    Left := 20;
    Right := Printer.PageWidth; // szerokosc strony
    Bottom := LineHeight * 2;
  end;

{ Wyswietl wycentrowany tekst mieszczacy sie w kwadracie "R". }
  DrawText(Printer.Handle, 
  'Service for programmers [http://www.programowanie.of.pl]', -1, R, DT_CENTER);

{
  Przed chwila wydrukowany zostal naglowek. Teraz do tej wartosci dodawana jest  liczba odpoiwadajaca wysokosci dwoch linii. Nastepnie rysowana zostaje pozioma  linia przedzielajca naglowek od wlasciwego tekstu.
}
  with Printer do
  begin
    Canvas.MoveTo(0, R.Top + LineHeight * 2);// ustaw kursor we właściwym miejscu
    Canvas.LineTo(R.Right, R.Top + LineHeight * 2); // rysuj linie
  end;
{
  Ta pela odpowiada za drukowanie poszczegolnych linii - od zerowej do konca  zawartosci zmiennej "PText".
}
  for I := 0 to PText.Count -1 do
  begin
    Inc(Line); // zwieksz wartosc aktualnie drukowanej linii
    if Line = LineCount then // Jezeli wiecej linii na stronie sie nie zmiesci...
    begin
      Line := 5; // ustaw na poczatku strony
      Printer.NewPage; // rozpocznij drukowanie nowej strony
    end;

    S := PText.Strings[i]; // do zmiennej "S" przypisz aktualnie drukowana linie
{
  Wydrukuj linie. Zostanie ona wydrukowana w miejscu okreslonym przez uzytkownika - tzn. poczatek drukowanej linii bedzie w punkcie oznaczonym przez zmienna "lMargin". Pozycja Y druokowanego tekstu okreslana bedzie przez pomnozenie aktualnie drukowanej linii przez wysokosc linii.
}
    Printer.Canvas.TextOut(lMargin, Line * LineHeight, S);
  end;

  Printer.EndDoc; // zakoncz drukowanie
end;

procedure TMainForm.btnPrintClick(Sender: TObject);
begin
  PrintText(memText.Lines); // wywolaj procedure
end;

end.

5 komentarzy

Taka mała rzecz. Jak wstawiłem to i drukowałem wieksze litery, a program (i pole Memo) były na cały ekran (rozdzielczość 1024/768) to linie ywszły po za kartkę :D

A może mi ktoś wytłumaczyć czym różni się RichEdit od Memo????

DO DUPY TO BYŁO

Jest troche roboty, ale można też tak

RichEdit1.Lines:= Memo1.Lines; RichEdit1.Print(); Richedit1.Lines.Clear;

Dla leniwych :)

Bardzo ciekawe!