В этой главе раскрывается, как встроить полноценный веб-клиент прямо в Qt-приложение и получить гибрид, который выглядит как нативный, работает быстро и при этом использует всю мощь современных веб-технологий. Вы обнаружите, почему профессиональные разработчики всё чаще делают ставку именно на Qt WebEngine.
Будет показано, как за несколько строк кода отобразить веб-страницу, как управлять историей переходов и отслеживать загрузку ресурсов. В тексте фигурируют конкретные цифры, архитектурные модули Qt6 и реальные примеры гибридных приложений, которые уже используют этот подход.
Если оставить эту главу на потом — есть риск продолжать писать избыточный код и терять время там, где всё уже решено.
Для закрепления материала доступны готовые к компиляции примеры и 16 бесплатных глав, позволяющих сразу применять подходы из книги на практике.
Самопроверка по главе
Почему в Qt5.4 движок WebKit заменили на Chromium, и какие преимущества это дало разработчикам?Ответ
Правильный ответ: Chromium обеспечил современную совместимость на всех платформах, полную интеграцию с Qt-экосистемой (сигналы/слоты, QML), возможность взаимодействия JS и C++ через WebChannel, а также компактность по сравнению с Electron.
Зачем в Qt6 модуль WebEngine разделили на три отдельных модуля: Core, Widgets и Quick?Ответ
Правильный ответ: Разделение позволяет приложениям на Qt Quick не нести избыточный код виджетов, снижая размер и повышая производительность приложений без классических виджетов.
Почему Qt WebEngine не предоставляет готовый полнофункциональный браузер как единый виджет?Ответ
Правильный ответ: Вместо этого предоставляется «конструктор» с компонентами, позволяющий разработчику создать браузер нужной конфигурации с использованием других виджетов Qt.
Что произойдет, если пользователь введет адрес www.example.com без указания протокола, и как это должно обрабатываться?Ответ
Правильный ответ: Метод load() может не распознать адрес корректно. Приложение должно проверять начало строки и автоматически добавлять https://, если протокол отсутствует.
Почему класс QWebEngineHistory автоматически удаляет дублирующиеся элементы при совпадении адресов?Ответ
Правильный ответ: Это предотвращает неконтролируемый рост списка истории до огромных размеров и делает историю навигации практически пригодной для использования.
В чем главная сложность загрузки веб-страниц, которую Qt WebEngine скрывает от разработчика?Ответ
Правильный ответ: Асинхронная загрузка множественных ресурсов (изображения, CSS, JS, фреймы), которые приходят независимо и в любом порядке, с обработкой возможных ошибок сети и сервера.
Какой сигнал нужно использовать для отображения прогресс-бара загрузки страницы, и что он передает?Ответ
Правильный ответ: Сигнал loadProgress() класса QWebEngineView, который передает целочисленное значение от 0 до 100, показывающее процент завершения загрузки.
Зачем соединять слоты back() и forward() QWebEngineView с кнопками, если история управляется автоматически?Ответ
Правильный ответ: Автоматическая навигация работает только при клике по ссылкам; кнопки дают пользователю явное управление историей для возврата к предыдущим страницам без поиска ссылок.
Что произойдет с пользовательским интерфейсом, если не обновлять поле адреса после перехода по ссылке?Ответ
Правильный ответ: Пользователь увидит устаревший адрес, не сможет корректно скопировать текущий URL или внести в него изменения, что нарушит базовую функциональность браузера.
Почему для проектов с WebEngine под Windows рекомендуется MSVC, а не MinGW?Ответ
Правильный ответ: MinGW может вызывать проблемы при работе с модулем WebEngine, тогда как MSVC 2017+ обеспечивает стабильную компиляцию проектов с этим модулем.
В каких случаях гибридное приложение (нативный код + веб-контент) более выгодно, чем чистое веб-приложение?Ответ
Правильный ответ: Когда нужен доступ к локальным ресурсам системы, нативная производительность интерфейса, интеграция с ОС или работа с данными вне веб (конфигураторы, панели управления).
Как должно приложение обработать ситуацию, когда loadFinished() вернул false?Ответ
Правильный ответ: Проинформировать пользователя об ошибке, например, вызвав метод setHtml() для отображения сообщения об ошибке загрузки страницы прямо в окне браузера.
Почему методы canGoBack() и canGoForward() важны для управления состоянием кнопок навигации?Ответ
Правильный ответ: Они предотвращают попытки навигации в несуществующие элементы истории, позволяя делать кнопки активными только когда переход действительно возможен.
В чем принципиальное отличие архитектуры VS Code (на Electron) от подхода Qt WebEngine?Ответ
Правильный ответ: Electron использует Chromium + Node.js с UI полностью на HTML/JS, тогда как Qt WebEngine встраивает веб-движок в нативное приложение, обеспечивая большую компактность и производительность.
Что может произойти, если забыть добавить webenginewidgets в pro-файл или CMake?Ответ
Правильный ответ: Компилятор выдаст ошибку “Unknown module(s)” или не найдет классы QWebEngineView; также возможно отсутствие модуля в минимальных сборках Qt, требующее установки через Maintenance Tool.
Практические задания
Простой уровень
Простой просмотрщик документации
Создайте приложение, которое отображает локальную HTML-документацию или справку. Добавьте кнопки “Назад”, “Вперед” и “Домой” (возврат к стартовой странице). Реализуйте индикатор загрузки страницы с помощью QProgressBar.
Подсказки: Используйте QWebEngineView для отображения. Соедините кнопки со слотами back(), forward() и reload(). Для индикатора подключите сигнал loadProgress() к setValue() прогресс-бара. Начальную страницу можно загрузить через load(QUrl::fromLocalFile(“путь/к/файлу.html”)).
Средний уровень
Браузер с управлением историей
Разработайте веб-браузер с полем ввода адреса, автоматической валидацией URL (добавление https:// при необходимости), управлением кнопками навигации (активны только когда доступен переход) и отображением списка посещенных страниц. Добавьте кнопку для очистки истории.
Подсказки: В slotGo() проверяйте начало строки методом startsWith(). Используйте QWebEngineHistory::canGoBack()/canGoForward() для управления состоянием кнопок. Получите доступ к истории через webView->page()->history(). Для списка страниц используйте методы items(), backItems() или forwardItems(). Очистка — метод clear().
Сложный уровень
Гибридное приложение с локальными и веб-ресурсами
Создайте приложение-конфигуратор, которое отображает веб-страницы с информацией о продуктах, но также позволяет загружать и сохранять конфигурацию в локальный JSON-файл. Реализуйте вкладки (QTabWidget) для одновременной работы с несколькими страницами, обработку ошибок загрузки с выводом информативного сообщения и возможность экспорта текущей страницы в PDF.
Подсказки: Создайте QTabWidget и добавляйте в него новые QWebEngineView. Для JSON используйте QJsonDocument. Обработку ошибок выполняйте в слоте loadFinished(bool). Для экспорта в PDF используйте webView->page()->printToPdf(). Синхронизируйте адресную строку с активной вкладкой через сигнал currentChanged() QTabWidget. Рассмотрите использование QWebChannel для взаимодействия между C++ и JavaScript.
💬 Присоединяйтесь к обсуждению!
Разобрались с интеграцией веб-контента в Qt-приложения? Возникли вопросы о том, когда стоит выбрать гибридный подход?
Поделитесь своим опытом создания веб-браузеров, расскажите о сложностях при работе с Qt WebEngine или помогите другим читателям найти оптимальное решение для их задач!