Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Программирование с использованием gtkmm 3. Печать

Оригинал: Programming with gtkmm 3
Авторы: Murray Cumming, Bernhard Rieder, Jonathon Jongsma, Ole Laursen, Marko Anastasov, Daniel Elstner, Chris Vine, David King, Pedro Ferreira, Kjell Ahlstedt
Дата публикации: 15 Октября 2013 г.
Перевод: А.Панин
Дата перевода: 28 марта 2014 г.

20. Печать

На уровне разрабатываемого приложения API печати gtkmm предоставляет диалоги, которые являются однообразными во всех приложениях и позволяют использовать стандартный API для рисования на основе библиотеки Cairo вместе с системой вывода текста на основе библиотеки Pango. В основе реализации данного обобщенного API лежат специфичные для платформ механизмы и специфичные для принтеров драйверы.

20.1. Объект операции печати PrintOperation

Основным объектом, создаваемым для каждой из операций печати, является объект на основе класса Gtk::PrintOperation. Для обработки результатов формирования страницы следует устанавливать обработчики для его сигналов или наследовать класс от лежащего в основе данного объекта класса и перекрывать виртуальные обработчики сигналов. Объект операции печати PrintOperation автоматически обрабатывает все настройки, касающиеся цикла печати.

20.1.1. Сигналы

Метод Gtk::PrintOperation::run() позволяет начать цикл печати, в процессе которого генерируются различные сигналы:
  • begin_print: Вы должны обрабатывать этот сигнал, так как на данном этапе вы должны создать и настроить набор объектов областей вывода текста на основе класса Pango::Layout с помощью передаваемого объекта контекста печати на основе класса Gtk::PrintContext, а также разделить ваш печатаемый документ на страницы.
  • paginate: Операция разделения документа на страницы может выполняться достаточно медленно, поэтому в том случае, если вы хотите следить за процессом разделения документа на страницы, вы можете осуществить вызов метода Gtk::PrintOperation::set_show_progress() с последующей обработкой данного сигнала.
  • Для каждой страницы, изображение которой должно быть сформировано, генерируются следующие сигналы:
    • request_page_setup: Предоставляет объект контекста печати PrintContext, номер страницы и объект настроек страницы на основе класса Gtk::PageSetup. Обрабатывайте этот сигнал в том случае, если вам необходимо модифицировать настройки страниц с доступом к настройками каждой из них.
    • draw_page: вы должны обрабатывать этот сигнал, предоставляющий объект контекста печати PrintContext и номер страницы. Объект контекста печати PrintContext должен использоваться для создания контекста Cairo на основе класса Cairo::Context, с помощью которого обрабатываемая страница должна прорисовываться. Для вывода текста следует осуществить обход набора объектов областей вывода текста на основе класса Pango::Layout, который вы создали в рамках обработчика сигнала "begin_print".
  • end_print: Обработчик данного сигнала является безопасным местом для освобождения любых ресурсов, относящихся к представленной объектом на основе класса Gtk::PrintOperation операции печати. В том случае, если вы используете специальный унаследованный от класса Gtk::PrintOperation класс, обычно проще выполнить описанные действия в дестукторе.
  • done: Данный сигнал генерируется в момент окончания печати и сообщает о том, что все предназначенные для печати данные были обработаны. Учтите, что передаваемый объект результата печати на основе класса Gtk::PrintOperationResult может сообщать о том, что произошла ошибка. В любом случае, вы, скорее всего, захотите уведомить пользователя о конечном результате операции.
  • status_changed: Генерируется всегда, когда изменяется статус задачи печати до ее завершения. Следует вызывать метод Gtk::PrintOperation::set_track_print_status() для отслеживания состояния задачи после начала печати. Для просмотра статуса следует использовать метод get_status() или метод get_status_string().

Справочная информация

20.2. Настройка параметров страницы

Класс операции печати Gtk::PrintOperation содержит метод с именем set_default_page_setup(), который устанавливает стандартный размер бумаги, ориентацию листа и размеры полей. Для показа диалога настройки страницы в вашем приложении следует использовать метод Gtk::run_page_setup_dialog(), который возвращает объект настроек страницы на основе класса Gtk::PageSetup, хранящий заданне с помощью диалога настройки. Используйте этот объект для обновления настроек объекта операции печати на основе класса Gtk::PrintOperation, для доступа к выбранным настройкам размера страницы типа Gtk::PaperSize и ориентации страницы типа Gtk::PageOrientation, а также к специфичным для принтера размерам полей.

Вы должны сохранить созданный на основе класса Gtk::PageSetup объект настроек страницы для того, чтобы иметь возможность использовать его в будущем в том случае, если диалог настроек страницы будет показан снова.

Например, это может быть сделано следующим образом:
//В рамках класса, унаследованного от класса Gtk::Window и хранящего объекты m_refPageSetup и m_refSettings в качестве дочерних объектов...
Glib::RefPtr<Gtk::PageSetup> new_page_setup = Gtk::run_page_setup_dialog(*this, m_refPageSetup, m_refSettings);
m_refPageSetup = new_page_setup;

Справочная информация

Координатная система Cairo в рамках обработчика сигнала "draw_page" автоматически поворачивается в соответствии с текущей ориентацией страницы. Она обычно располагается внутри установленных принтером полей, но вы можете изменить ее расположение с помощью метода Gtk::PrintOperation::set_use_full_page(). Стандартной единицей измерения являются пиксели устройства. Для выбора других единиц измерения используйте метод Gtk::PrintOperation::set_unit().

20.3. Вывод текста

Вывод текста осуществляется с помощью библиотеки Pango. Создание объекта области вывода текста на основе класса Pango::Layout осуществляется с помощью метода Gtk::PrintContext::create_pango_layout(). Объект контекста печати также предоставляет метрики страницы, которые могут быть получены с помощью методов get_width() и get_height(). Количество страниц может быть установлено с помощью вызова метода Gtk::PrintOperation::set_n_pages(). Для непосредственного вывода текста с помощью библиотеки Pango в рамках обработчика сигналов "on_draw_page" следует получить контекст Cairo с помощью метода Gtk::PrintContext::get_cairo_context() и показать текст Pango, представленный объектом на основе класса Pango::LayoutLines, который появится на странице с заданным номером.

Обратитесь к примеру для ознакомления с реализацией описанного механизма.

20.4. Асинхронные операции

По умолчанию метод Gtk::PrintOperation::run() возвращает управление тогда, когда операция печати завершается. Если вам необходимо выполнить операцию без блокировки, следует осуществить вызов метода Gtk::PrintOperation::set_allow_async(). Учтите, что метод set_allow_aync() не поддерживается на всех платформах, однако сигнал "done" будет генерироваться в любом случае.

Метод run() может возвращать результат PRINT_OPERATION_RESULT_IN_PROGRESS. Для отслеживания статуса и обработки результата выполнения операции печати или ошибки вам придется реализовать обработчики сигналов "done" и "status_changed":

Эти обработчики могут быть установлены, к примеру, следующим образом:
// В рамках метода класса ExampleWindow...
Glib::RefPtr<PrintOperation> op = PrintOperation::create();
// ...настройка объекта операции печати...
op->signal_done().connect(sigc::bind(sigc::mem_fun(*this, &ExampleWindow::on_printoperation_done), op));
// выполнение операции печати
Во-вторых, следует проверять наличие ошибки и устанавливать обработчик для сигналов "status_changed". Например, это может быть сделано следующим образом:
void ExampleWindow::on_printoperation_done(Gtk::PrintOperationResult result, const Glib::RefPtr<PrintOperation>& op)
{
  if (result == Gtk::PRINT_OPERATION_RESULT_ERROR)
    //вывод уведомления для пользователя
  else if (result == Gtk::PRINT_OPERATION_RESULT_APPLY)
    //Обновление параметров объекта настроек печати PrintSettings с использованием параметров объекта операции печати PrintOperation.

  if (! op->is_finished())
    op->signal_status_changed().connect(sigc::bind(sigc::mem_fun(*this, &ExampleWindow::on_printoperation_status_changed), op));
}
Наконец, следует проверить результат. Примером кода проверки может служить следующий код:
void ExampleWindow::on_printoperation_status_changed(const Glib::RefPtr<PrintFormOperation>& op)
{
  if (op->is_finished())
    //операция печати завершена
  else
    //получение статуса операции с помощью метода get_status() или get_status_string()

  //обновление состояния пользовательского интерфейса
}

20.5. Экспорт в файл формата PDF

В диалоге печати доступна функция "Печатать в файл", которая не требует дополнительной реализации. Однако, иногда она бывает полезной для генерации файла формата pdf непосредственно на уровне кода. Например, это может быть сделано следующим образом:
Glib::RefPtr<Gtk::PrintOperation> op = Gtk::PrintOperation::create();
// ...установка параметров объекта операции печати...
op->set_export_filename("test.pdf");
Gtk::PrintOperationResult res = op->run(Gtk::PRINT_OPERATION_ACTION_EXPORT);

20.6. Расширение функций диалога печати

Вы можете добавить специальную вкладку в диалог печати следующим образом:
  • После установки заголовка вкладки с помощью метода Gtk::PrintOperation::set_custom_tab_label() следует создать новый виджет и вернуть соответствующий ему объект из обработчика сигнала "create_custom_widget". Скорее всего, вы захотите сделать этот виджет контейнерным для упаковки каких-либо других виджетов.
  • После работы с диалогом следует получать данные от созданных виджетов с помощью обработчика сигналов "custom_widget_apply".
Хотя сигнал "custom_widget_apply" и передает объект виджета, который вы создали ранее, для упрощения кода вы можете сделать виджеты, которые будут участвовать в процессе ввода пользователем каких-либо данных, дочерними виджетами класса. К примеру, предположим, что вы объявили виджет ввода строки на основе класса Gtk::Entry с именем m_Entry дочерним виджетом вашего класса CustomPrintOperation:
Gtk::Widget* CustomPrintOperation::on_create_custom_widget()
{
  set_custom_tab_label("Моя специальная вкладка");

  Gtk::Box* hbox = new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 8);
  hbox->set_border_width(6);

  Gtk::Label* label = Gtk::manage(new Gtk::Label("Введите какой-либо текст: "));
  hbox->pack_start(*label, false, false);
  label->show();

  hbox->pack_start(m_Entry, false, false);
  m_Entry.show();

  return hbox;
}

void CustomPrintOperation::on_custom_widget_apply(Gtk::Widget* /* widget */)
{
  Glib::ustring user_input = m_Entry.get_text();
  //...
}

Пример в директории examples/book/printing/advanced демонстрирует описанный подход.

20.7. Предварительный просмотр

Стандартный диалог печати из состава GTK+ содержит кнопку предварительного просмотра, но вы также можете вызвать окно предварительного просмотра напрямую из кода приложения:
// в рамках класса, унаследованного от класса Gtk::Window...
Glib::RefPtr<PrintOperation> op = PrintOperation::create();
// ...настройка параметров объекта операции печати...
op->run(Gtk::PRINT_OPERATION_ACTION_PREVIEW, *this);

На платформах Unix стандартный механизм предварительного просмотра использует внешнюю программу для просмотра документов. На платформе Windows при этом будет показан стандартный системный диалог предварительного просмотра. В случае необходимости вы можете изменить это поведение и показывать специальный диалог предварительного просмотра. Обратитесь к примеру в директории /examples/book/printing/advanced.


Следующий раздел : 20.8. Пример.