Печать HTML-документа в Qt 5.8

23 января 2017 года вышла Qt версии 5.8, в которой появилась поддержка печати полноценных HTML-документов.

До этого возможность напечатать документ тоже была. Можно было:

  • Использовать метод QTextDocument::Print(). Но приходилось ограничиваться небольшими возможностями HTML и CSS.
  • Использовать метод QWebFrame::print(), который существовал пока не вышла Qt 5.6. Потом в Qt был окончательно заменен веб-движок и поддержка печати пропала.
  • Использовать печать в PDF с помощью метода QWebEnginePage::printToPdf(), который появился в Qt 5.7. Но печать в PDF — это не печать через принтер.
  • Вывести видимую часть страницы на печать методом QWebEngineView->render(). Но это плохой обходной путь, так как не вся страница будет выведена на печать и потребуется отобразить страницу.

В Qt 5.8 появился метод QWebEnginePage::print(), который выводит на печать HTML-документы без отрисовки в окне и поддерживает современные возможности HTML, CSS и JavaScript.

Следующий код выводит HTML-документ на принтер.

#include <QDebug>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrinterInfo>
#include <QWebEnginePage>

void MainWindow::on_printButton_clicked()
{
    QPrinter * printer = new QPrinter();

    QPrintDialog printDialog(printer, this);
    if (printDialog.exec() != QDialog::Accepted) {
        return;
    }

    QWebEnginePage * page = new QWebEnginePage;

    page->setHtml("<html><body>Привет<body/></html>");

    connect(
        page,
        &QWebEnginePage::loadFinished,
        [page, printer] (bool ok) {
            if (!ok) {
                qDebug() << "Загрузка документа провалилась."; 
                delete page;
                delete printer;
                return;
            }

            page->print(printer, [page, printer](bool ok) {
                if (ok) {
                    qDebug() << "Документ напечатан.";
                }
                else {
                    qDebug() << "Печать документа провалилась.";
                }
        
                delete page;
                delete printer;
            });
        }
    );
}

В файле проекта (*.pro) нужно подключить два модуля с помощью следующей строчки.

QT += printsupport webenginewidgets

В коде используются лямбда-выражения, которые появились в C++11. Это конструкции вида: [...] (...) {...}, анонимные функции внутри функций. В Qt 5.8 по умолчанию включен C++11.

Класс QWebEnginePage обрабатывает, отрисовывает и печатает документы асинхронно с основным кодом программы, поэтому код в лямбда-функциях выполняется уже после того, как завершится метод on_printButton_clicked().

Надо внимательно следить за удалением объектов, чтобы не возникло утечки памяти и ошибки сегментации, особенно при печати нескольких документов в цикле. Объект принтера может быть одним, а выводимых на печать документов несколько. Тогда объект принтера надо удалять, после печати последнего документа, и не забывать, что печать происходит асинхронно. То есть функция print() завершается еще до вывода документа на печать.

Но и у этого способа печати есть огромный недостаток. К сожалению модуль Qt WebEngine, в который входит класс QWebEnginePage, недоступен при сборке проекта с помощью MinGW в Виндовс. Собрать проект в Виндовс можно только с помощью Visual Studio.

Реклама