Различные статьи по Qt и c++

Печать страниц справки и экспорт в PDF из встроенного браузера

Введение

Пользователи иногда хотят распечатать конкретную страницу справки или сохранить её как PDF для последующего использования без необходимости держать приложение открытым — например, при настройке оборудования без доступа к компьютеру рядом. В статье добавим возможность печати и экспорта в PDF к справочному браузеру, построенному в статье 165, используя инфраструктуру печати Qt, более подробно разбираемую в отдельном цикле статей про печать и PDF.

Концепция

QTextBrowser наследует QTextEdit, который поддерживает печать своего содержимого через стандартный механизм QTextDocument::print() — документ, лежащий в основе браузера, можно напрямую отправить на QPrinter (показывая диалог печати пользователю) или на QPdfWriter (для прямого сохранения в PDF без диалога принтера). Поскольку базовый текстовый движок Qt используется и в QTextBrowser, и в общей системе печати, эта интеграция не требует какого-то специального кода, разбирающего HTML заново — печатается ровно то же отрендеренное представление документа, что показывается на экране.

Пример кода: Печать страниц справки

#include "helpwindow.h"
#include <QPrinter>
#include <QPrintDialog>
#include <QFileDialog>
#include <QPdfWriter>

void HelpWindow::onPrintCurrentPage()
{
    QPrinter printer(QPrinter::HighResolution);
    QPrintDialog dialog(&printer, this);
    dialog.setWindowTitle("Печать страницы справки");

    if (dialog.exec() != QDialog::Accepted) {
        return;
    }

    m_browser->document()->print(&printer);
}

void HelpWindow::onExportCurrentPageToPdf()
{
    const QString defaultName = m_browser->documentTitle().isEmpty()
                                    ? "справка.pdf"
                                    : m_browser->documentTitle() + ".pdf";

    const QString filePath = QFileDialog::getSaveFileName(
        this, "Сохранить страницу справки как PDF", defaultName, "PDF файлы (*.pdf)");

    if (filePath.isEmpty()) {
        return;
    }

    QPdfWriter pdfWriter(filePath);
    pdfWriter.setPageSize(QPageSize(QPageSize::A4));
    pdfWriter.setResolution(300);

    m_browser->document()->print(&pdfWriter);

    qDebug() << "Страница справки сохранена как PDF:" << filePath;
}
// Добавление кнопок в панель инструментов окна справки (расширение HelpWindow из статьи 165)
auto *toolbar = addToolBar("Действия");
toolbar->addAction("Печать", this, &HelpWindow::onPrintCurrentPage);
toolbar->addAction("Сохранить как PDF", this, &HelpWindow::onExportCurrentPageToPdf);

Пояснения к коду

onPrintCurrentPage() создаёт стандартный QPrintDialog, позволяющий пользователю выбрать принтер и настройки печати, а затем вызывает m_browser->document()->print(&printer) — это печатает именно тот документ (с уже разрешёнными изображениями через loadResource(), как было настроено в статье 165), который в данный момент отображается в браузере, со всем форматированием.

onExportCurrentPageToPdf() показывает альтернативный путь без диалога принтера — QPdfWriter, настроенный на конкретный размер страницы и разрешение, передаётся в тот же метод print(), и результат сохраняется напрямую в выбранный пользователем файл через QFileDialog::getSaveFileName(). Использование m_browser->documentTitle() для формирования предложенного имени файла — приятная деталь UX, избавляющая пользователя от необходимости придумывать имя файла самостоятельно.

Подводные камни

  • Печать только текущей видимой страницы, а не всей справки целиком. Пользователь, желающий распечатать «всю справку» или конкретный раздел с подразделами, должен будет повторить операцию для каждой страницы по отдельности — для печати целых разделов целиком нужна отдельная функциональность, которая бы программно «склеивала» содержимое нескольких страниц в один QTextDocument перед печатью, что не реализовано в базовом варианте.
  • Изображения, встроенные через схему qthelp://, должны быть полностью загружены к моменту печати. Если печать инициируется до того, как все ресурсы текущей страницы успели разрешиться через loadResource() (что обычно происходит синхронно и быстро для локального контента .qch, но стоит иметь в виду как потенциальный источник проблем), на печатной версии могут отсутствовать изображения.
  • Разрешение PDF, не соответствующее ожиданиям при последующем масштабировании. Установка setResolution(300) определяет качество растеризации содержимого при экспорте — для текстовой справки без сложной растровой графики это обычно избыточно высокое значение, увеличивающее размер итогового файла без видимого выигрыша в качестве, тогда как для страниц с детальными скриншотами интерфейса более высокое разрешение действительно может быть оправдано.
  • Отсутствие поддержки печати интерактивных элементов, если справка содержит встроенное видео или интерактивные виджеты (актуально при использовании QWebEngineView вместо QTextBrowser, статья 172) — печать через QTextDocument::print() работает только для контента, представимого в виде текстового документа, и не применима напрямую к WebEngineView, для которого нужен отдельный API печати (QWebEnginePage::printToPdf()), не совпадающий с показанным в этой статье подходом.