Sign in Join
Wiki copytemporary

Using the printer/pl

Deutsch · English · Español · Polski · 中文(中国) · 日本語

Korzystanie z drukarki

Wstęp

Drukowanie jest łatwe w Lazarus/FreePascal. Musisz jednak wykonać kilka wymaganych kroków. Najpierw pierwsze kroki. Po tych pierwszych krokach możesz przejść do bardziej zaawansowanego drukowania. W tym artykule omówiono wymagane kroki zebrane z różnych stron forum i przykładów. Po wykonaniu podstawowych kroków wydrukujemy trochę tekstu. Na koniec podana jest wskazówka dotycząca bardziej zaawansowanego drukowania.

Note: Obecnie drukowanie w WinCE (przy użyciu pakietu Printers4Lazarus) nie jest obsługiwane.

Podstawowe kroki

Aby móc korzystać z drukarek, musisz wykonać następujące czynności:

  1. Dodaj pakiet Printer4Lazarus do wymagań projektu.
  2. Dodaj moduł Printers do sekcji uses w swoim module.
  3. Użyj istniejącego obiektu Printer.

Dodanie pakietu Printer4Lazarus do wymagań projektu

Pakiet Printer4Lazarus definiuje podstawową drukarkę i zapewnia drukowanie niezależne od platformy. Dzięki temu na różnych platformach można korzystać z poniższych rzeczy.

W Lazarus IDE wykonaj następujące czynności:

  1. W menu Projekt kliknij Inspektor projektu. Wyświetlane jest okno z widokiem drzewa, a jedna z gałęzi nazywa się Wymagane pakiety. Domyślnie gałąź Wymagane pakiety pokazuje pakiet LCL.
  2. Kliknij przycisk Dodaj, czyli przycisk ze znakiem plus u góry okna.
  3. Otwórz stronę Nowy wymóg.
  4. Z listy Nazwa pakietu wybierz Printer4Lazarus.
  5. Kliknij OK'''.
  6. Printer4Lazarus jest teraz pokazywany w gałęzi Wymagane pakiety.

Dodanie modułu Printers do sekcji uses twojego modułu

Ten krok jest prosty, a wynik może wyglądać tak:

pascal
unit MainUnit;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Forms, Printers;

Korzystanie z istniejącego obiektu Printer

Załóżmy, że chcesz kliknąć przycisk, aby wydrukować tekst. W formularzu umieść przycisk o nazwie PrintBtn, a w zdarzeniu OnClick możesz teraz użyć:

pascal
procedure TForm1.PrintBtnClick(Sender: TObject);
const
  LEFTMARGIN = 100;
  HEADLINE = 'Data i czas mojego pierwszego wydruku to: ';
var
  YPos, LineHeight, VerticalMargin: Integer;
  SuccessString: String;
begin
  with Printer do
  try
    BeginDoc;
    Canvas.Font.Name := 'Courier New';
    Canvas.Font.Size := 10;
    Canvas.Font.Color := clBlack;
    LineHeight := Round(1.2 * Abs(Canvas.TextHeight('I')));
    VerticalMargin := 4 * LineHeight;
    // No to jedziemy
    YPos := VerticalMargin;
    SuccessString := HEADLINE + DateTimeToStr(Now);   
    Canvas.TextOut(LEFTMARGIN, YPos, SuccessString);
  finally
    EndDoc;
  end;
end;

Czy napisałem podstawowy i prosty? Powyższy przykład jest nieco złożony. Oprócz podstawowego tekstu wyjściowego w pogrubionej linii, zawiera również przykład formatowania tekstu.

Od słów kluczowych begin do end; dzieją się następuje rzeczy:

Note: Na niektórych forach sugeruje się, że do prawidłowego funkcjonowania wymagane jest użycie PrintDialog (okno dialogowe wyboru drukarki), ale nie uznałem tego prawdę (nigdy więcej).
\

Tip: Niestety jest to prawda, choć nie pełna. Przy pierwszym uruchomieniu powyższego przykładu może się zdarzyć, że pojawi się błąd Access Violation. Nie wiem jeszcze jaka jest przyczyna tego błędu. Gdy położymy PrintDialog na formatce, to błąd już się nie pojawia. Co więcej, można ten PrintDialog usunąć, a błąd już nie wraca. (Ten problem zaobserwowałem w systemie Fedora. Niestety teraz nie mogę go odtworzyć. Prawdopodobnie problem dotyczy plików konfiguracyjnych w katalogu .lazarus)

Następne kroki

Po wykonaniu powyższych podstawowych kroków, możesz wykonać kolejne kroki. Zostawiam to tobie czytelniku, abyś spróbował:

W dystrybucji Lazarusa znajduje się przykładowy projekt, który wykorzystuje do drukarki drukowanie w trybie Raw. Ten przykład można znaleźć w następującej lokalizacji $(lazarusdir)\components\printers\samples\rawmode\rawmodetest.lpi. Kolejny przykład pokazuje, jak wybrać inną drukarkę: $(lazarusdir)\components\printers\samples\dialogs\selectprinter.lpi.

Zaawansowane kroki: sterowanie drukowaniem

Obiekt drukarki umożliwia przede wszystkim rysowanie na płótnie i wysyłanie tego obrazu do drukarki. Jeśli będziemy kontynuować ścieżką pokazaną powyżej, użyjesz metod płótna drukarki, aby narysować tekst, elipsy, romby i co tylko chcesz.

Nie może to jednak zainteresować żadnego poważnego programisty. Pracujesz nad doskonalszym programem CAD lub jeszcze innym sortownikiem plików graficznych i chcesz wydrukować wspaniały rezultat swojego programu na swojej drukarce. Próba przetłumaczenia idealnego obrazu na wywołania metod na płótnie nie jest dobrą drogą: ponieważ ty już masz gotowy obraz.

Każda kontrolka, którą umieścisz w formularzu, również rysuje obraz na obiekcie TCanvas, podobnie jak drukarka. Możemy to wykorzystać do przeniesienia obrazu z ekranu do drukarki.

Wyobraź sobie, że zamierzasz stworzyć program podglądu wydruku. Tworzysz formularz i na tym formularzu umieszczasz TPanel. Ten panel zapewni ładne szarawe tło podglądu. Na panelu umieszczasz kolejny obiekt TPanel o nazwie page (strona). Ten panel page będzie biały i reprezentuje papier. Możesz ładnie dopasować rozmiar strony.

Na tej stronie umieściliśmy obiekt TShape, na przykład ładny czerwony, zaokrąglony prostokąt. Teraz spróbuj wykonać następujące czynności w metodzie zdarzenia PrintBtnClick:

pascal
MyPrinter.BeginDoc;
  page.PaintTo(myPrinter.Canvas, 0, 0);
MyPrinter.EndDoc;

Co tu się dzieje?

Zmiana rozmiaru papieru

Drukarka zużywa znacznie więcej pikseli na cal na papierze niż monitor używa pikseli na cal na ekranie. W rezultacie wydruk końcowy, który jest przekierowywany z ekranu do drukarki, ma na papierze rozmiar raczej niewielki. Skalowanie i kontrolowanie układu jest ważne dla dobrego wyglądu wydruku. Byłoby miło, gdybyś mógł mieć kopię tego, co widzisz na ekranie w dokładnym rozmiarze.

Na razie nie dążymy do ideału, tylko do idei. Jak wspomniano wcześniej, kontrolki nie mają własnego płótna, ale opierają się na płótnie kontenera lub właściciela. Istnieją jednak komponenty, które mają własne płótno. Gdy wybrałem TBitMap, działa w następujący sposób:

pascal
procedure TForm1.PrintBtnClick(Sender: TObject);
var
  MyPrinter : TPrinter;
  myBitMap : TBitMap;
begin
  myBitMap := TBitMap.Create;
  myBitMap.Width := page.Width;
  myBitMap.Height := page.Height;
  page.BorderStyle:=bsNone;
  page.PaintTo(myBitMap.Canvas, 0, 0);
  page.BorderStyle:=bsSingle;
  //
  MyPrinter := Printer;
  MyPrinter.BeginDoc;
    //page.PaintTo(myPrinter.Canvas, 0, 0);
    //myPrinter.Canvas.Draw(0,0, myBitMap);
    myPrinter.Canvas.CopyRect(Classes.Rect(0, 0, myPrinter.PaperSize.Width, myPrinter.PaperSize.Height),
       myBitMap.Canvas, Classes.Rect(0, 0, myBitMap.Width, myBitMap.Height));
  MyPrinter.EndDoc;
  myBitMap.Free;
end;

Aby to zadziałało, nie używaj modułu Windows. Moduł Windows ma inne definicje dla Rect. To, co widzisz w przykładzie, działa w następujący spsób:

Ale zauważ jedną rzecz, że w tym procesie strona (page) jest powiększana. Printer.papersize jest znacznie większy niż rozmiar mapy bitowej (bitmap), ale proces kopiowania ładnie wypełnia docelowy prostokąt. Tak więc, kiedy chcemy to zrobić, musimy upewnić się, że wymiary page mają taki sam stosunek szerokości do wysokości, jak wymiar papieru. Możesz dowiedzieć się, jak to zrobić.

Problem z tym sposobem pracy polega oczywiście na tym, że na wydrukowanym papierze pojawią się piksele ekranu. Jak powiedziałem, nie jest to sposób idealny, ale pokazuje zasadę działania. Kontrolki nie mają własnego płótna; aby wydrukować kontrolki, najpierw malujemy je na obiekcie, który ma swoje własne płótno: TBitMap. Teraz wiesz, jak to działa, możesz wymyślić sposób na tworzenie pięknych dzieł sztuki lub dokumentów. Będzie to wymagało obiektów, które rysują się poprawnie w TPanel o niskiej rozdzielczości, ale także na TBitMap o wysokiej rozdzielczości. Ale to jest temat na inny artykuł.

Zwykłe zadania

Pamiętaj, że Printer: TPrinter to singleton (może istnieć tylko jedna instancja obiektu tej klasy). Jest to pojedynczy obiekt, który obsługuje wszystkie drukarki zainstalowane w systemie. Konkretna realizacja w systemie (WinAPI, Cocoa itp.) powinna implementować ten obiekt.

Wyliczanie dostępnych drukarek

Lista drukarek systemowych jest dostępna we właściwości Printer.Printers.

Właściwość Printers jest typu TStrings, która zawiera nazwę każdej drukarki.

delphi
procedure TForm1.FormShow(Sender: TObject);
begin
  ListBox1.Items.AddStrings(Printer.Printers);
end;

Wybranej nazwy podanej we właściwości Printers należy użyć ustawiając drukarkę za pomocą metody SetPrinter().

Internals: każda klasa implementująca klasę TPrinter powinna implementować metodę DoEnumPrinters(). DoEnumPrinters powinien wypełnić przekazane parametry listy nazwami drukarek. Oczekuje się, że nazwa drukarki jest unikalna.

DoEnumPrinters() powinien zwrócić domyślną drukarkę systemową jako pierwszy wpis (indeks 0) na liście.

Zmiana/Wybór drukarki

Domyślnie obiekt Printer powinien mieć wstępnie wybraną drukarkę „domyślną systemową”. (Z tym, że w systemie Windows 10 i nowszych może nie być ustawiona drukarka domyślna.)

W razie potrzeby drukarka może zostać zmieniona przez użytkownika za pośrednictwem PrinterDialogs lub programowo.

W celu programowej zmiany drukarki należy użyć metody SetPrinter lub właściwości PrinterIndex.

Obie metody opierają się na drukarkach wymienionych w PrintersProperty.

delphi
procedure TForm1.Button2Click(Sender: TObject);
begin
  Printer.SetPrinter(ListBox1.ItemIndex);
end;

:*Jeśli określony indeks wynosi -1, to znaczy, że wybrana została drukarka domyślna

delphi
procedure TForm1.Button2Click(Sender: TObject);
begin
  Printer.SetPrinter(ListBox1.GetSelectedText);
end;

:* Zauważ, że istnieje specjalna nazwa dla metody SetPrinter. Jeśli nazwa jest określona jako '*', wybierana jest pierwsza (domyślna) dostępna drukarka. Każda z metod może zgłosić wyjątek, jeśli określona nazwa lub indeks nie istnieje.

Internals: Klasa pochodna od TPrinter powinna implementować metodę DoSetPrinter() używając parametru aName jako nazwy wybranej drukarki. Metoda nie wymaga specjalnej obsługi nazwy '*', ponieważ jest ostrożna na wyższym poziomie niż TPrinter.

Przygotowywanie rozmiaru papieru

Uwaga: jeśli używasz wielu drukarek (zwłaszcza jeśli używasz specjalistycznych drukarek używających niestandardowego rozmiaru papieru, takiego jak „A4” (europejski) lub „US Letter” (USA)), zawsze chcesz przygotować właściwy rozmiar papieru. Możliwe, że nowo wybrana drukarka nie obsługuje papieru, który był obsługiwany przez poprzednio wybraną drukarkę. Rozmiar papieru nie jest resetowany automatycznie, więc musisz to zrobić samodzielnie.

Istnieją trzy właściwości PaperSize, które można wywołać w celu zresetowania i przygotowania rozmiaru papieru:

Oto przykład kodu, który ponownie odczytuje listę wybranych rozmiarów papierów

delphi
procedure TForm1.ListBox1SelectionChange(Sender: TObject; User: boolean);
begin
  // zmieniono drukarkę. Ale wybrany rozmiar papieru nadal może być właściwy
  Printer.PrinterIndex := ListBox1.ItemIndex; 
  ListBox2.Clear;
  // wywołanie SupportedPapers wymuszające weryfikację rozmiaru papieru
  ListBox2.Items.AddStrings(Printer.PaperSize.SupportedPapers); 
end;

Oto przykład resetowania rozmiaru papieru przy użyciu właściwości DefaultPaperName.

delphi
procedure TForm1.ListBox1SelectionChange(Sender: TObject; User: boolean);
begin
  // zmieniono drukarkę. Ale wybrany rozmiar papieru nadal może być właściwy
  Printer.PrinterIndex := ListBox1.ItemIndex; 
  // wywołanie DefaultPaperName wymuszające weryfikację rozmiaru papieru
  Printer.PaperSize.DefaultPaperName;
end;

Internals: Pochodna klasa TPrinter powinna poprawnie implementować:

Jeśli metoda wewnętrzna nie zwraca żadnych rozmiarów papieru, klasa TPrinter zastępuje je „domyślnymi” rozmiarami papieru (takimi, które przypuszczalnie obsługiwane są przez większość drukarek). Domyślne rozmiary to np.: Letter, A4, Legal. Jednak dobra implementacja klasy TPrinter powinna wypełniać rozmiary stron.

Należy wypełnić także dwa pola:

Liczba punktów zależy od aktualnie wybranego DPI drukarki (ang. dots per inch - liczba punktów obrazu na cal długości). (Zauważ, że istnieją dwa różne DPI dla pomiarów poziomych i pionowych).

Oto tabela przedstawiająca różnicę w rozmiarze A4 w zależności od rozmiaru DPI

DPI Zwrócony rozmiar w TPaperRect
72 595 x 842
300 2480 x 3507
600 4960 x 7014
1200 9920 x 14028

Zobacz także


From the Free Pascal wiki, page "Using the printer/pl", as it stood on 2022-02-06 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.