Шаг 30.
Библиотека OWL.
Простейший пример печати

    На этом шаге мы рассмотрим пример программы, выводящей данные на принтер.

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

#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\printer.h>
#include <owl\dc.h>
#include <owl\editfile.rh>
#include "pr30_1.rc"

//Класс приложения
class TApp: public TApplication
{
  public:
	 TApp():TApplication(){}
	 void InitMainWindow();
};

//Класс основного окна
class TWndw : public TFrameWindow
{
  public:
        TWndw(TWindow *parent, const char far *title);
        ~TWndw();
  protected:
        TPrinter *printer;
        void Paint(TDC &dc, BOOL, TRect&);
        void CmFilePrint();

        DECLARE_RESPONSE_TABLE(TWndw);
};

DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow)
      EV_COMMAND(CM_FILEPRINT, CmFilePrint), 
END_RESPONSE_TABLE;

// Класс печати.
class TWndwPrintout : public TPrintout
{
  protected:
       TWindow *window;
  public:
       TWndwPrintout (const char *title, TWindow *w);
       void PrintPage (int, TRect &rect, unsigned);
};

TWndw::TWndw(TWindow *parent, const char far *title):
		  TFrameWindow(parent,title, 0, FALSE)
{
	// Добавить меню к главному окну.
	AssignMenu("MENU_1");
	// Определить расположение и размеры окна.
	Attr.X=50;
	Attr.Y=50;
	Attr.W=GetSystemMetrics(SM_CXSCREEN)/3;
	Attr.H=GetSystemMetrics(SM_CXSCREEN)/4;
       // Создать объект окна TPrinter. 
       printer = new TPrinter;
}

// TWndw::~TWndw()
// Это деструктор главного окна.
TWndw::~TWndw() 
{
    delete printer;
}

//TWndw::CmFilePrint()
// Эта функция реагирует на команду Print меню File.
void  TWndw::CmFilePrint()
{
  // Если объект принтера существует...
  if (printer)
  {
     // Создать экземпляр объекта печати. 
     TWndwPrintout printout("Тест принтера", this);
     // Напечатать объект печати. 
     printer->Print(this, printout, TRUE);
  }
}

//TWndw::Paint()
// Эта функция переопределяет функцию Paint() из
// TWindow и реагирует на сообщения WM_PAINT, которые
// Windows посылает окну, если оно должно быть
// перерисовано. Однако, вызывая эту функцию с
// контекстом устройства TPrinter в качестве
// первого параметра, можно ее использовать для
// распечатки содержимого окна на принтере.
void TWndw::Paint(TDC &dc, BOOL, TRect&)
{
  // Нарисовать прямоугольник.
  dc.Rectangle (10,10,100,100);
}
//TWndwPrintout::TWndwPrintout()
// Это конструктор объекта  печати.
TWndwPrintout::TWndwPrintout(const char *title, TWindow *w) :
     TPrintout(title) 
{
  // Сохранить указатель окна для последующего использования.
  window = w;
}

// TWndwPrintout::PrintPage()
// Эта функция вызывается для каждой страницы
// документа. Именно в этом фрагменте программа
// создает изображение, которое появится на принтере.
void TWndwPrintout::PrintPage (int, TRect &rect, unsigned) 
{
  // Вызвать функцию главного окна Paint(), 
  // передавая контекст устройства объекта 
  // TPrinter, а не контекст устройства окна. 
  window->Paint (*DC, FALSE, rect);
}

void TApp::InitMainWindow()
{
  TFrameWindow *wndw= new TWndw(0,"Использование принтера");
  SetMainWindow(wndw);
}

int OwlMain(int,char *[])
{
  return TApp().Run();
}

    Файл ресурсов:

#ifndef WORKSHOP_INVOKED
#include "windows.h"
#endif

#ifdef RC_INVOKED

#include <owl\printer.rc>

#define CM_EXIT        24310
#define CM_FILEPRINTT  24337

MENU_1 MENU
{
 POPUP "&File"
 {
  MENUITEM "&Print...", CM_FILEPRINTT
  MENUITEM SEPARATOR
  MENUITEM "E&xit", CM_EXIT
 }
}
#endif
Текст этого приложения можно взять здесь.

    После запуска программы, приведенной в примере, вы увидите окно, изображенное на рисунке 1.


Рис.1. Главное окно приложения

    Это окно имеет рабочую область, содержащую простой прямоугольник и меню File с двумя командами - Print и Exit. Если вы выбираете команду Print, появляется показанное на рисунке 2 диалоговое окно Print, позволяющее выбрать размеры страницы, установить качество печати и печать или в файл, или на принтер.


Рис.2. Настройка печати

    Вы можете даже получить доступ к диалоговому окну Свойства, используя одноименную кнопку. Выбором кнопки ОК диалогового окна запускается процесс печати, при этом содержимое окна посылается на принтер.

    Посмотрите сначала на конструктор главного окна:

class TWndw : public TFrameWindow
{
  public:
        TWndw(TWindow *parent, const char far *title);
        ~TWndw();
  protected:
        TPrinter *printer;
        void Paint(TDC &dc, BOOL, TRect&);
        void CmFilePrint();

        DECLARE_RESPONSE_TABLE(TWndw);
};

DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow)
      EV_COMMAND(CM_FILEPRINT, CmFilePrint), 
END_RESPONSE_TABLE;

    Как следует из фрагмента, приведенного выше, главное окно является производным от класса TFrameWindow и имеет, в качестве защищенного члена-данного, указатель на объект TPrinter (чтобы использовать класс TPrinter библиотеки OWL, вы должны включить в свою программу заголовочный файл PRINTER.H). Кроме этого конструктора, класс главного окна TWndw имеет деструктор, функцию Paint(), и единственную функцию отклика на сообщение CmFilePrint(), которую библиотека OWL вызывает в том случае, когда пользователь выбирает из меню File команду Print. Конструктор основного окна имеет следующий вид:

TWndw::TWndw(TWindow *parent, const char far *title):
		  TFrameWindow(parent,title, 0, FALSE)
{
	// Добавить меню к главному окну.
	AssignMenu("MENU_1");
	// Определить расположение и размеры окна.
	Attr.X=50;
	Attr.Y=50;
	Attr.W=GetSystemMetrics(SM_CXSCREEN)/3;
	Attr.H=GetSystemMetrics(SM_CXSCREEN)/4;
       // Создать объект окна TPrinter. 
       printer = new TPrinter;
}

    Как это обычно бывает в программах библиотеки OWL, конструктор главного окна сначала назначает меню данному окну, а затем устанавливает положение и размеры окна на экране путем установки полей Attr окна. После этого конструктор динамически создает объект принтера, используя оператор new для вызова конструктора TPrinter. Tpeбуется только одна строка в программе для создания контекста устройства принтера, который закрепляется за принтером пользователя, установленным по умолчанию. Другими словами, после конструирования объекта TPrinter программа может сразу же посылать данные на принтер.

    Многие программы, приведенные в шагах, не включают деструкторы в основное окно. Однако весьма часто программа должна делать некоторую чистку, прежде чем закрыть приложение. Конструктор основного окна представляет собой прекрасное место программы для выполнения подобных заключительных операций:

TWndw::~TWndw() 
{
  delete  printer;
}

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

    Посмотрите на функцию главного окна Print():

void TWndw::Paint(TDC &dc, BOOL, TRect&)
{
  // Нарисовать прямоугольник.
  dc.Rectangle (10,10,100,100);
}

    Все, что она делает - это рисует небольшой прямоугольник в рабочей области главного окна. Однако, как вы скоро увидите, Paint() выполняет в этой программе двойную функцию, создавая также посылаемое на принтер изображение. Запуск задачи печати происходит, если пользователь выбрал из меню File команду Print, что является сигналом библиотеке OWL для вызова функции CmFilePrint():

void  TWndw::CmFilePrint()
{
  // Если объект принтера существует...
  if (printer)
  {
     // Создать экземпляр объекта печати. 
     TWndwPrintout printout("Тест принтера", this);
     // Напечатать объект печати. 
     printer->Print(this, printout, TRUE);
  }
}

    Эта функция сначала проверяет, не равен ли 0 указатель принтера. Затем она создает объект печати из класса TWndwPrintout программы и вызывает функцию Print() объекта принтера для печати. Это все, что делается в данной программе для организации работы с принтером. Однако, большая часть усилий программиста в этой программе направлена на определение объекта Printout (напоминаем, что объект принтера представляет собой устройство печати, а объект вывода на печать - распечатываемый документ).

    Так как обработка объекта TPrinter проста, вам чрезвычайно редко (если вообще когда-либо) придется создавать свой собственный класс принтера из TPrinter. Используйте TPrinter в том виде, как он представлен в примере. Однако вы должны создать свой собственный класс TPrintout, так как TPrintout является абстрактным классом, содержащим несколько функций, которые вы должны переопределить в своем приложении. В примере класс вывода на печать TWndwPrintout выглядит следующим образом:

class TWndwPrintout : public TPrintout
{
  protected:
       TWindow *window;
  public:
       TWndwPrintout (const char *title, TWindow *w);
       void PrintPage (int, TRect &rect, unsigned);
};

    Этот класс имеет единственный защищенный член-данное, который хранит указатель главного окна приложения. Вы вскоре узнаете, почему программе необходим такой указатель. Данный класс имеет также конструктор, имеющий параметрами указатель на имя печатаемого объекта и указатель на главное окно приложения. PrintPage() переопределяет функцию в классе Printout и отвечает за печать содержания каждой страницы документа. PrintPage() вызывается объектом TPrinter для каждой страницы многостраничного документа. Три параметра Printpage() представляют собой номер текущей страницы, прямоугольник, содержащий количество страниц в многостраничном документе, и целое беззнаковое число, содержащее битовые флаги для описания текущего многостраничного документа. Если вы не используете разделение текста на страницы, вы можете проигнорировать параметры rect и flags.


    Замечание. Печать целой страницы очень часто является трудной, требующей больших затрат времени и памяти, задачей для Windows-программ. Это особенно справедливо в тех случаях, когда распечатываемый документ содержит растровую графику. Для ускорения и упрощения процесса печати Windows-программ часто используют способ, называемый разбиением полосы (banding), который представляет собой процесс разбивки документа на ряд небольших прямоугольников, или полос, которые могут быть напечатаны индивидуально. Составленные вместе, они дадут требуемое изображение. Разделение на полосы может даже сэкономить дисковую память, необходимую для печати документа, ибо весь документ целиком не нужно будет выводить в буфер на диске.

    Конструктор объекта печати имеет следующий вид:

TWndwPrintout::TWndwPrintout(const char *title, TWindow *w) :
     TPrintout(title) 
{
  // Сохранить указатель окна для последующего использования.
  window = w;
}

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

    Функция PrintPage() класса также короткая:

void TWndwPrintout::PrintPage (int, TRect &rect, unsigned) 
{
  // Вызвать функцию главного окна Paint(), 
  // передавая контекст устройства объекта 
  // TPrinter, а не контекст устройства окна. 
  window->Paint (*DC, FALSE, rect);
}

    Эта функция просто вызывает функцию главного окна Paint(), но в этот раз с контекстом устройства принтера, а не контекстом устройства окна. Результатом этого будет вывод изображения прямоугольника на принтер, а не на экран. Придавая такие двойные обязанности функции главного окна Paint(), совсем просто вывести содержимое окна на принтер.

    На следующем шаге мы рассмотрим ресурсы объекта "принтер".




Предыдущий шаг Содержание Следующий шаг