Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Глава 15. Объекты печати

             Один из наиболее трудных аспектов программирования в Windows
        - это  вывод  на принтер.  ObjectWindows путем использования ряда
        модулей и инкапсуляции поведения устройства печати и самой распе-
        чатки делает печать более простой.

             Данная глава  описывает  основы процесса печати,  после чего
        описываются следующие задачи:

             * Построение объекта принтера.

             * Создание распечатки.

               - Печать документа.

               - Печать содержимого окна.

             * Передача распечатки на принтер.

             * Выбор другого принтера.

             * Настройка конфигурации принтера.

                        Почему печать представляет трудности?
        -----------------------------------------------------------------

             С одной стороны печать в Windows достаточно проста. Вы може-
        те использовать для генерации распечатки те же функции  GDI,  что
        используются для  вывода образов на экран.  Для вывода текста ис-
        пользуется функция TextOut,  а для вычерчивания прямоугольника  -
        Rectangle.

             С другой стороны,  процесс осложняется, так как Windows тре-
        бует непосредственного "общения" с драйверами принтера через  вы-
        зовы Escape  или  получения  адреса DeviceMode или ExtDeviceMode.
        Это еще более осложняется требованием Windows,  чтобы  приложение
        считывало имя  драйвера устройства из файла WIN.INI.  Кроме того,
        устройства печати обладают большими возможностями проверки допус-
        тимости и возможностями разрешения, чем видеоустройства.

             ObjectWindows не  может  преодолеть  все препятствия на этом
        пути, но делает процесс печати более простым и легким для понима-
        ния.

                                Печать в ObjectWindows
        -----------------------------------------------------------------

             Модуль ObjectWindows OPrinter предусматривает для  упрощения
        печати два объекта - TPrinter и TPrintout. TPrinter инкапсулирует
        доступ к устройствам печати.  Он предоставляет возможность конфи-
        гурирования принтера, выводя диалог, в котором пользователь может
        выбрать нужный принтер,  а также установить параметры печати, та-
        кие как  графическое  разрешение или ориентация (горизонтальная и
        вертикальная) печати.

             TPtintout инкапсулирует задачу печати документа.  К принтеру
        этот объект имеет такое же отношение, как TWindow - к экрану. Ри-
        сование на экране выполняется методом Paint  объекта  TWindow,  а
        печать на  принтере - методом PrintPage объекта TPrintout.  Чтобы
        напечатать что-то на принтере,  приложение должно передать методу
        Print объекта TPrinter экземпляр TPrintout.

                             Построение объекта принтера
        -----------------------------------------------------------------

             В большинстве случаев приложению требуется в  каждый  момент
        времени доступ только к одному принтеру. Простейшим способом реа-
        лизации этого является задание в объекте основного  окна  поля  с
        именем Printer (типа PPrinter), которые другие объекты в програм-
        ме вызывают для целей печати.  Чтобы сделать  принтер  доступным,
        поле Printer должно указывать на экземпляр TPrinter.

             В большинстве приложений это просто.  Основное окно приложе-
        ния инициализирует объект принтера,  который использует  заданный
        по умолчанию принтер, указанный в WIN.INI:

             constructor TSomeWindow.Init(AParent: PWindowsObject;
                                          ATitle: PChar);
             begin
                Inherited Init(AParent, ATitle);
                 .
                 .
                 .
                Printer := New(PPrinter, Init);
             end;

             В некоторых  случаях может возникать необходимость использо-
        вать в приложении различные принтеры  одновременно  из  различных
        окон. В  этом  случае  постройте  объект принтера в конструкторах
        каждого такого окна,  затем смените устройство принтера  на  один
        или более  таких  принтеров.  Если программа использует различные
        принтеры, но не одновременно, то возможно лучше использовать один
        и тот  же  объект принтера и при необходимости выбирать различные
        принтеры.

             Хотя вы можете сомневаться насчет переопределения  конструк-
        тора TPrinter для использования принтера,  отличного от заданного
        в системе по умолчанию, рекомендуемой процедурой является исполь-
        зование конструктора  по  умолчанию,  а  затем смена связанного с
        объектом устройства. См. раздел "Выбор другого принтера".


                                 Создание распечатки
        -----------------------------------------------------------------

             Единственной "хитрой" частью процесса печати в ObjectWindows
        являются создание распечатки.  Этот процесс аналогичен  написанию
        метода Paint для объекта окна: вы используете графические функции
        Windows для генерации в контексте устройства нужного графического
        образа.  Контекст  устройства  оконного объекта обрабатывает ваши
        взаимодействия с устройством экрана; аналогичным образом контекст
        устройства распечатки изолирует вас от устройства печати.

                   Примечание: Графические  функции  Windows поясняются в
              Главе 17.

             Чтобы создать объект распечатки, постройте новый тип, произ-
        водный от  TPtintout,  который переопределяет PrintPage.  В очень
        простых случаях это все,  что требуется  сделать.  Если  документ
        имеет размер более одной страницы, то вам нужно также переопреде-
        лить HasNextPage для возврата True.  Текущий номер страницы пере-
        дается в качестве параметра PrintPage.

             Объект распечатки  имеет поля,  содержащие размер страницы и
        контекст  устройства,  который уже инициализирован для  принтера.
        Объект принтера  устанавливает  значения,  вызывая  метод объекта
        распечатки SetPrintParams. Используйте контекст устройства объек-
        та распечатки в любом вызове графических функций Windows.

             Модуль OPrinter  включает в себя два специализированных объ-
        екта распечатки,  которые показывают диапазон сложности  распеча-
        ток. Объект  TWindowPrintout,  печатающий содержимое окна,  очень
        прост. TEditPrintout,  который печатает  содержимое  управляющего
        элемента редактирования,  очень  сложен,  так как имеет множество
        возможностей.

                                   Печать документа
        -----------------------------------------------------------------

             Windows рассматривает   распечатку   как  последовательность
        страниц, поэтому задачей вашего объекта распечатки является прев-
        ращение документа  в последовательность станичных образов для пе-
        чати Windows.  Аналогично тому как оконные  объекты  используются
        для отображения образов на экране дисплея, объекты распечатки ис-
        пользуются для печати образов на принтере.

             ObjectWindows предусматривает абстрактный объект  распечатки
        TPrintout, из которого вы можете создать производные объекты рас-
        печатки. Вам нужно переопределить в  TPrintout  только  несколько
        методов.

             Ваши объекты распечатки должны делать следующее:

             * Устанавливать параметры принтера.

             * Подсчитывать страницы.

             * Отображать каждую страницу в контексте устройства.

             * Указывать, есть ли еще страницы.

             Остальная часть  этой  главы  ссылается  на пример программы
        PrnTest, записанной на ваших дистрибутивных дискетах  под  именем
        PRNTEST.PAS. PrnTest  считывает  текстовый файл в набор строк,  а
        затем по команде печатает документ.  Объект  PrnTest  описывается
        следующим образом:

             type
               PTextPrint = ^TTextPrint;
               TTextPrint = object(TPrintout);
                 TextHeight, LinesPerPage, FirstOnPage, LastOnPage:
                    Integer;
                 TheLines; PCollection;
                 constructor Init(ATitle: PChar;
                                  TheText: PPCharCollection);
                 function GetDialogInfo(var Pages: Intger): Boolean;
                                  virtual;
                 function HasNextPage(Page: Word): Boolean; virtual;
                 procedure SetPrintParams(ADC: HDC; ASize: TPoint);
                                  virtual;
                 procedure PrintPage(Page: Word; var Rect: TRect;
                                  Flags: Word); virtual;
             end;

                              Задание параметров печати
        -----------------------------------------------------------------

             Перед запросом распечатки документа объект принтера  предос-
        тавляет вашему  документу  возможность разбивки на страницы.  Для
        этого вызываются два метода объекта распечатки - SetPrintParams и
        GetDialogInfo.

             Функция SetPrintParams   предназначена   для   инициализации
        структур данных, которые могут потребоваться для получения эффек-
        тивной распечатки отдельных страниц.  SetPrintParams - это первая
        возможность вашей распечатки обратиться к контексту устройства  и
        задать для  принтера  размер  страницы.  Приводимый ниже фрагмент
        программы показывает     пример     переопределенного      метода
        SetPrintParams.

             Если вы переопределяете SetPrintParams,  убедитесь в  вызове
        наследуемого  метода,  устанавливающего значения полей распечатки
        объекта.

                                   Подсчет страниц
        -----------------------------------------------------------------

             После вызова SetPrintParams объект печати вызывает булевскую
        функцию GetDialogInfo. GetDialogInfo задает информацию, необходи-
        мую для вывода на экран диалогового блока, позволяющего пользова-
        телю выбрать перед печатью диапазон страниц. В подсчете страниц в
        GetDialogInfo и  индикации  вывода  диалогового блока имеются два
        аспекта.

             Функция GetDialogInfo воспринимает единственный параметр-пе-
        ременную Pages,  которую она должна устанавливать в число страниц
        в документе или в 0, если она не может подсчитать страницы. Возв-
        ращаемое значение  равно True,  если вы хотите вывести диалоговый
        блок, и False для подавления его вывода.

             По умолчанию GetDialogInfo устанавливает Pages в 0 и возвра-
        щает True,  что означает,  что она не знает,  сколько может полу-
        читься страниц, и что перед печатью  будет  выводиться диалоговый
        блок. GetDialogInfo обычно переопределяется для установки Pages в
        число страниц в документе и возвращает True.

             Например, PrnTest подсчитывает, сколько строк текста выбран-
        ного шрифта  может поместиться в области печати в SetPrintParams,
        а затем использует это число для подсчета количества страниц, ко-
        торые нужно напечатать в GetDialogInfo:

             procedure TTextPrint.SetPrintParams(ADC: HDC;
                                                 ASize: TPoint);
             var TextMetrics: TTextMetric;
             begin
               inherited SetPrintParams(ADC, ASize);  { установить DC и
                                                        размер Size }
               GetTextMetrics(DC, TextMetrics); { получить информацию о
                                                  размере текста }
               TextHeigh := TextMetrics.tmHeight; { вычислить высоту
                                                    строки }
               LinesPerPages := Size.Y div TextHeight; { и число строк
                                                         на странице }
             end;

             function TTextPtint.GetDialogInfo(var Pages: Integer):
                                               Boolean);
             begin
               Pages:= TheLines^.Count div LinesPerPage + 1;
               GetDialogInfo := True { вывод перед печатью диалогового
                                       блоки }
             end;

                                Печать каждой страницы
        -----------------------------------------------------------------

             Когда объект принтера предоставляет возможность разбивки до-
        кумента на  страницы,  то  для печати каждой страницы он вызывает
        метод PrintPage объекта  распечатки.  Процесс  распечатки  только
        части документа, которому принадлежит данная страница, аналогичен
        определению того,  какую часть прокручиваемого окна нужно отобра-
        жать на экране.  Например, можно отметить подобие методов отобра-
        жения окна и отображения страницы:

             procedure TTextWindow.Paint(PaintDC: HDC;
                var PaintInfo: TPaintStruct);
             var
                Line: Integer;
                TextMetrics: TTextMetric;
                TheText: PChar;

                function TextVisible(ALine: Integer): Boolean;
                begin
                  with Scroller^ do
                     TextVisible := IsVisible(0, (ALine div YUnit) +
                        YPos, 1, Attr.W div YUnit);
                  end;

             begin
               GetTextMetrics(PaintDC, TextMetrics);
               Scroller^.SetUnits(TextMetrics.tmAveCharWidth,
                   TextMetrics.tmHeight);
               Line := 0;
               while (Line < FileLines^.Count) and TextVisible(Line) do
               begin
                 TheText := PChar(FileLines^.At(Line));
                 if TheText <> nil then
                   TextOut(PaintDC, 0, Line * Scroller^.YUnit, TheText,
                      StrLen(TheText));
                 Inc(Line);
               end;
             end;

             procedure TTextPrint.PrintPage(Page: Word; var Rect: TRect;
                                            Flags: Word);
             var
               Line: Integer;
               TheText: PChar;
             begin
               FirstOnPage := (Page - 1) * LinesPerPage;
               LastOnPage := (Page * LinesPerPage) - 1;
               if LastOnPage >= TheLines^.Count then
                 LastOnPage := TheLines^.Count - 1;
               for Line := FirstOnPage to LastOnPage do
               begin
                 TheText := Theines^.At(Line);
                 if TheText <> nil then
                   TextOut(DC, 0, (Line - FirstOnPage) * TextHeight,
                       TheText, StrLen(TheText));
               end;
             end;

             При написании методов PrintPage следует иметь в виду следую-
        щее:

             * Независимость от устройств. Убедитесь, что в вашем коде не
               делается предположений относительно масштаба, коэффициента
               относительного удлинения  или  цветах.  Для различных уст-
               ройств видеоотображения и печати эти характеристики  могут
               отличаться, так что в программе следует избегать такой за-
               висимости.

             * Возможности  устройств.  Хотя  большинство  видеоустройств
               поддерживают все операции GDI, некоторые принтеры этого не
               делают. Например, многие устройства печати (такие как гра-
               фопостроители)  совсем не воспринимают графических изобра-
               жений.  При выполнении сложных задач  вывода  в  программе
               следует вызывать функцию API Windows GetDeviceCaps,  кото-
               рая возвращает важную информацию о данном устройстве выво-
               да.

                             Указание оставшихся страниц
        -----------------------------------------------------------------

             У объектов  распечатки имеется также последняя обязанность -
        указать объекту принтера,  имеются ли после данной  страницы  еще
        печатаемые страницы.  Метод  HasNextPage  воспринимает в качестве
        параметра номер строки и возвращает значение  Boolean,  указываю-
        щее, существуют ли еще страницы.  По умолчанию HasNextPage всегда
        возвращает значение  False.  Чтобы  напечатать несколько страниц,
        ваши объекты распечатки  должны  переопределять  HasNextPage  для
        возврата True,  если документ имеет больше страниц для печати,  и
        False, если переданным параметром является последняя страница.

             Например, PrnTest  сравнивает  номер  последней напечатанной
        строки с последней строкой в файле и определяет,  нужно ли  печа-
        тать еще страницы:

             function TTextPrint.HasNextPage(Page: Word): Boolean;
             begin
               HasNextPage := LastOnPage < TheLines^.Count - 1;
             end;

             Убедитесь, что HasNextPage возвращает в некоторой точке зна-
        чение False.  Если HasNextPage всегда возвращает True, то процесс
        печати попадет в бесконечный цикл.

                             Другие соглашения по печати
        -----------------------------------------------------------------

             Объекты распечатки  содержат также несколько других методов,
        которые вы  можете  при  необходимости   переопределить.   Методы
        BeginPrintint и EndPrinting вызываются, соответственно, перед пе-
        чатью и после печати любого документа.  Если вам требуется специ-
        альная установка,  вы можете выполнить ее в BeginPrinting и отме-
        нить в EndPrinting.

             Печать страниц выполняется  последовательно.  То  есть,  для
        каждой страницы   в  последовательности  принтер  вызывает  метод
        PrintPage. Однако, перед первым вызовом PrintPage объект принтера
        вызывает BeginDocument,  передавая номер первой и последней стра-
        ницы, которые будут печататься. Если для вашего документа при пе-
        чати страниц, отличных от первой, требуется специальная подготов-
        ка, переопределите метод BeginDocument.  После распечатки послед-
        ней страницы вызывается соответствующий метод EndDocument.

             Может потребоваться     также     переопределение     метода
        GetSelection. GetSelection указывает в своем возвращаемом булевс-
        ком значении,  имеет ли документ выделенную часть.  Если это так,
        диалоговое окно печати предоставляет вам возможность  распечатать
        только эту выделенную часть.  Позицию выделения указывают два па-
        раметра-переменных Start и Stop.  Например, TEditPrintout интерп-
        ретирует Start и Stop как позиции символов, но может представлять
        также строки текста, страницы и т.д.

                                Печать содержимое окна
        -----------------------------------------------------------------

             Поскольку окно не разбивается на несколько страниц,  и окон-
        ные объекты уже знают,  как отображаться в контексте  устройства,
        простейшим  видом генерируемой распечатки является копия содержи-
        мого окна.

             Чтобы еще более облегчить эту общую операцию,  ObjectWindows
        обеспечивает дополнительный     вид    объекта    распечатки    -
        TWindowPrint. Любой оконный объект ObjectWindows может без  моди-
        фикации печатать свое содержимое в объект TWindowPrintout. Объек-
        ты распечатки масштабируют образ  для  заполнения  нужного  числа
        страниц и поддерживают коэффициент относительного удлинения.

             Создание объекта распечатки окна требует только одного шага.
        Все, что требуется сделать - это построить  объект  печати  окна,
        передавая ему строку заголовка и указатель на окно,  которое тре-
        буется напечатать:

             PImage := New(PWindowPrintout, Init('Заголовок',
                                                        PSomeWindow));

             Часто возникает необходимость в том,  чтобы окно само созда-
        вало свою распечатку, возможно в ответ на команды меню:

             procedure TSomeWindow.CMPrint(var Msg: TMessage);
             var P: PPrintout;
             begin
               P := New(PWindowPrintout, Init('Дамп экрана', @Self));
               { передать образ на экран }
               Dispose(P, One);
             end;

             TWindowPrintout не предусматривает разбивки на страницы. При
        печати документа вам нужно печатать каждую страницу отдельно,  но
        так как окна не имеют страниц,  вам нужно напечатать только  один
        образ. Окно уже знает,  как создать  этот образ - оно имеет метод
        Paint. TWindowsPrintout печатается путем вызова метода Paint окна
        объекта с контекстом устройства печати вместо контекста дисплея.

                             Вывод распечатки на принтер
        -----------------------------------------------------------------

             При наличии объекта принтера и объекта распечатки  фактичес-
        кая печать  выполняется  достаточно  просто,  независимо от того,
        происходит это из документа или из окна.  Все, что вам нужно сде-
        лать - это вызов метода Paint объекта принтера, передача указате-
        ля на порождающее окно и указателя на объект распечатки:

             Printer^.Print(PParentWindow, PPrintoutObject);

             В этом случае порождающее окно - это окно,  к которому будут
        присоединены все всплывающие диалоговые блоки (например,  состоя-
        ния принтера или сообщений об ошибках).  Обычно это  будет  окно,
        генерирует команду печати, такое как основное окно со строкой ме-
        ню. В процессе печати для предотвращения  передачи  множественных
        команд печати это окно запрещается.

             Предположим, у  вас есть приложение,  основное окно которого
        является экземпляром TWidGetWindow.  В меню этого окна вы  можете
        выбрать команду  меню  для печати содержимого окна,  генерирующую
        команду cm_Print.  Метод реакции на сообщения может иметь следую-
        щий вид:

             procedure TWidgetWindow.CMPrint(var Msg: TMessage);
             var P: PPrintout;
             begin
               P := New(PWindowPrint, Init('Widgets', @Self));
               Printer^.Print(@Self, P);
               Dispose(P, Done);
             end;

                                Выбор другого принтера
        -----------------------------------------------------------------

             Когда у вас в приложении есть  объект  принтера,  вы  можете
        связать его с любым установленным в Windows устройстве печати. По
        умолчанию TPrinter  использует  заданный  по  умолчанию   принтер
        Windows (как это определено в разделе устройств файла WIN.INI).

             Существует два способа задания альтернативного принтера: не-
        посредственно в программе и через диалоговое окно пользователя.


                             Выбор принтера пользователем
        -----------------------------------------------------------------

             Наиболее общим способом назначения другого принтера является
        вывод диалогового окна, предоставляющего пользователю возможность
        выбора из списка установленных устройств печати.  TPtinter делает
        это автоматически при вызове его метода Setup.  Как  показано  на
        Рис.  15.1,  Setup  использует  для этого диалогового окна объект
        TPrinterSetupDlg.

        +---------------------------------------------------------------+
        |#=#XXXXXXXXXXXXXXXXXXXSelectPrinterXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
        +---------------------------------------------------------------|
        |                                                               |
        |      Printer and port:                                        |
        |      +--------------------------------------------+-+         |
        |      |PostScript Printer on LPT1:                 |v|         |
        |      +--------------------------------------------+-+         |
        |   +-----------+         +-----------+         +-----------+   |
        |   |####OK#####|         |##Setup####|         |##Cancel###|   |
        |   +-----------+         +-----------+         +-----------+   |
        |                                                               |
        +---------------------------------------------------------------+

             Рис. 15.1 Диалоговое окно задания принтера.

                         Настройка конфигурации принтера

             Одна из командных кнопок в диалоге выбора принтера позволяет
        пользователям изменить конфигурацию конкретного принтера.  Кнопка
        Setup выводит диалоговый блок конфигурации,  определенной в драй-
        вере принтера.  Ваше приложение не может управлять внешним  видом
        или функциями диалогового блока конфигурации драйвера.

                           Назначение конкретного принтера
        -----------------------------------------------------------------

             В некоторых  случаях  вам  может потребоваться назначить для
        своего объекта принтера специфическое устройство печати. TPrinter
        имеет метод SetDevice, который именно это и делает.

             SetDevice воспринимает в качестве параметров три строки: имя
        устройства, имя драйвера и имя порта.
                              Назад | Содержание | Вперед
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...