Qt как открыть ссылку в браузере
О кроссплатформенной библиотеке Qt слышали, наверное, многие. О движке отображения веб-страниц WebKit тем более. Не так давно первое стало содержать обертку над вторым, примеры создания браузеров в 50 строчек найти не сложно. Тем не менее о том, как получать доступ к отдельным элементам веб-страницы из Qt-кода написано не много.
В данном описании я предполагаю, что люди обладают начальными познаниями в PyQt (я учил по Саммерфилду), и смутным представлением о JavaScript. Свой уровень я характеризую, именно таким, так что заранее извиняюсь за ошибки, особенно в описании ява-скрипта. Несмотря на то что в качестве языка использован Python у программистов C++/Qt вопросов тоже быть не должно.
Тестовые примеры запускались на PyQt-4.7.3, версия Python-2.6.6-r1 под ОС GNU/Linux. Из программ понадобится браузер с отладкой JS (Chrome, например) и PyQt IDE на ваше усмотрение, я использую Eric4.
Пример 1. Браузер, над которым мы будем издеваться
def adjustLocation(self):
self.locationEdit.setText(self.webView.url().toString())
def adjustTitle(self):
if self.__progress = 100:
self.setWindowTitle(self.webView.title())
else :
self.setWindowTitle(QString( "%1 (%2%)" ).arg(self.webView.title()).arg(self.__progress))
def setProgress(self, p):
self.__progress = p
self.adjustTitle()
def finishLoading(self):
self.__progress = 100
self.adjustTitle()
if __name__ == "__main__" :
import sys
app = QApplication(sys.argv)
prog = BaseBrowser()
prog.show()
sys.exit(app.exec_())
* This source code was highlighted with Source Code Highlighter .
Браузер представляет некую вариацию на тему браузеров из обучающих примеров по C++/Qt и PyQt, в последующих двух примеров мы будем его наследовать. Я понимаю, что так программы, даже маленькие, не пишут, и программа не должна быть одним классом, но баланс между кол-вом кода, его наглядностью и правильностью архитектуру я соблюдаю как могу.
Итак, браузер наш умеет не многое, но может загружать и отображать введенную страницу, для этого используется виджет QWebView, стандартные сигналы создаваемые этим виджетом мы привязали к слотам нашего браузера, что позволяет программе знать программе о смене заголовку текущей веб-страницы SIGNAL(«titleChanged(QString)»), прогрессе загрузки SIGNAL(«loadProgress(int)») и окончании загрузки — SIGNAL(«loadFinished(bool)»). Кроме этого создается поле QlineEdit для ввода адресса страницы и кнопка для перехода к этой веб-странице, либо по нажатию «Enter» либо по щелчку на кнопке.
Запускаем браузер, пробуем в работе, офигиваем от скорости работы «голого» WebKit. Пока ничего особенного мы не написали. Наш браузер даже по ссылкам не по всем переходит.
Пример 2. DOM-деревья и доступ к их элементам из Qt
Вообще, о структуре HTML страниц лучше бы, почитать отдельно, в двух предложениях это описать проблематично. В общем-то, если вы будете делать из офлайновую оболочку к какому либо веб-интерфейсу, ява-скрипт нужно будет все-таки выучить, по-крайней мере ту его часть, которая относится к доступу к данным. Итак, любой современный браузер позволяет получить доступ к содержимому веб-страницы представляя его в в виде дерева узлов, каждый узел которого представляет собой элемент, атрибут, текстовый, графический или любой другой объект. Узлы связаны между собой отношениями родительский-дочерний (да, эта строка из википедии). При помощи интерпретатора JavaScript к узлам этого дерева можно получить доступ. Откроем наш браузер и зайдем на все тот же yandex.ru (надеюсь их не накроет хабраэффектом). Сколько вы видите ссылок над поисковой строкой?
Щелкните по списку ссылок и откройте их в меню разработчика (в Chrome это — «проверить элемент» в контекстном списке). Так мы увидим положение текущего элемента в дереве. Список имеет незамысловатый и является таблицей. Переключитесь в JavaScript консоль и попробуйте выбрать эту таблицу:
document.getElementById("tabs").
Посмотрите сколько в ней строк:
document.getElementById("tabs").rows.length
И сколько столбцов:
document.getElementById("tabs").rows(0).cells.length.
Теперь получим такой же результат в нашем браузере.
class SimpleJavaScript(BaseBrowser):
def __init__(self, parent = None):
super(SimpleJavaScript, self).__init__(parent)
self.jsButton = QPushButton( "ExecuteJS" )
self.connect(self.jsButton, SIGNAL( "clicked()" ), self.jsScript)
self.jsStringEdit = QLineEdit()
self.jsStringEdit.setSizePolicy(QSizePolicy.Expanding, self.jsStringEdit.sizePolicy().verticalPolicy())
self.jsStringEdit.setText( "document.getElementById(\"tabs\").rows(0).cells.length" )
self.connect(self.jsStringEdit, SIGNAL( "returnPressed()" ), self.jsScript)
self.jsReturnText = QTextEdit()
self.layout.addWidget(self.jsStringEdit, 2, 0, 1, 1)
self.layout.addWidget(self.jsButton, 2, 1, 1, 1)
self.layout.addWidget(self.jsReturnText, 3, 0, 1, 2)
def jsScript(self):
jsString = self.jsStringEdit.text()
jsReturn = self.webView.page().currentFrame().evaluateJavaScript(jsString)
self.jsReturnText.setPlainText(jsReturn.toString())
if __name__ == "__main__" :
import sys
app = QApplication(sys.argv)
ui = SimpleJavaScript()
ui.show()
sys.exit(app.exec_())
* This source code was highlighted with Source Code Highlighter .
Пример 3. Создание офлайн контролов
Адрес домашней страницы на этот раз выбран таким поскольку у меня карточка ATI и сижу я под Линуксом, кто знает, тот поймет, что это не от большой любви. На самом деле на странице множество контролов типа Select, для одного из которых мы создадим эквивалент.
class JSSelectList(QAbstractListModel):
def __init__ (self, _id, _jsFunc, parent = None):
super(JSSelectList, self).__init__(parent)
self.id = _id
self.jsFunc = _jsFunc
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return QVariant()
if role == Qt.DisplayRole:
jsstring = QString( "document.getElementById('%1').options[%2].textContent" ).arg(self.id).arg(index.row())
jsreturn = self.jsFunc(jsstring)
return jsreturn.toString().trimmed()
def rowCount(self, index=QModelIndex()):
jsstring = QString( "document.getElementById('%1').length" ).arg(self.id)
jsreturn = self.jsFunc(jsstring)
ok = False
count, ok = jsreturn.toInt()
return count if ok else 0
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role != Qt.DisplayRole:
return QVariant()
else :
return self.id
class JSComboBoxDemo(BaseBrowser):
def __init__(self, parent = None):
super(JSComboBoxDemo, self).__init__(parent)
self.vendorComboBox = QComboBox()
id = QString( "productLine" )
self.vendorListModel = JSSelectList(id, self.webView.page().currentFrame().evaluateJavaScript)
self.vendorComboBox.setModel(self.vendorListModel)
self.connect(self.vendorComboBox, SIGNAL( "currentIndexChanged(int)" ), self.setSelectOnWebPage);
self.connect(self.webView, SIGNAL( "loadFinished(bool)" ), self.initComboBox)
self.layout.addWidget(self.vendorComboBox, 2, 0, 1, 1)
self.webView.load(QUrl( "http://www.amd.com" ))
def setSelectOnWebPage(self, new_id):
jsstring = QString( "document.getElementById('productLine').selectedIndex=%1" ).arg(new_id)
self.webView.page().currentFrame().evaluateJavaScript(jsstring)
def initComboBox(self):
self.vendorComboBox.setCurrentIndex(0)
if __name__ == "__main__" :
import sys
app = QApplication(sys.argv)
ui = JSComboBoxDemo()
ui.show()
sys.exit(app.exec_())
* This source code was highlighted with Source Code Highlighter .
При создании таких элементов GUI как таблица, список, dropdown (не знаю как правильно перевести) Qt позволяет использовать удобный MVC подход. Вам нужно лишь описать доступ к вашей модели данных — вам нужно лишь наследовать ваше представление данных от встроенного абстрактного класса и прицепить его к стандартному контролу (у Саммерфилда, это вроде бы 14 глава). В данном случае используется QAbstractListModel, из параметров ей передается только функция исполнения JS и название select`а на странице. Все переопределения стандарты.
В самом примере тоже все достаточно понятно, кроме двух соединений типа сигнал-слот, на которые хотелось бы обратить ваше внимание.
Во-первых, бесполезно пытаться выполнить JavaScript до загрузки страницы, поэтому воспользуемся тем, что при окончании загрузки виджет QWebView формирует сигнал SIGNAL(«loadFinished(bool)»), о котором я уже говорил в первом примере.
self.connect(self.webView, SIGNAL("loadFinished(bool)"), self.initComboBox)
В противном случае, если запихнуть строку
в __init__ ни какой инициализации первым значением не произойдет — evaluateJavaScript ничего не вернет, так как страница еще не успеет загрузиться.
Во-вторых, нам нужна синхронизация в обе стороны:
self.connect(self.vendorComboBox, SIGNAL("currentIndexChanged(int)"), self.setSelectOnWebPage)
Аналогичным образом можно синхронизировать практически всю информацию на странице, нажимать кнопки, загружать информацию.
Буду рад, если информация окажется для кого-то полезной. Всех с Рождеством и прошедшим Новым Годом.
Ж. Бланшет, М. Саммерфилд. Qt 4: Программирование GUI на C++.
Mark Summerfield. Rapid GUI Programming with Python and Qt.
Другие источники:
Различные интернет сайты по JavaScript и PyQt, исходный код интернет-браузера Arora.
Ну кто из нас не хочет написать свой браузер? Да ладно, не отпирайтесь мысли про браузер, точно были. Так вот, Qt имеет класс QWebView, который позволяет работать с браузерным движком webkit, на котором написан chromium, а соответственно и chrome и многие другие браузеры. Поэтому практически использовав десяток строк кода можно сделать приложение, которое сможет отобразить страницу веб-сайта.
Итак, приложение будет следующим. Имеется адресная строка QLineEdit и виджет QWebView. При вводе адреса сайта в адресную строку и нажатии клавиши Enter будет запускаться получение страницы сайта и отображение её в QWebView. При клике по ссылке на странице адрес ссылки будет отображаться в адресной строке и будет загружаться новая странице в виджете.
Структура проекта для работы с QWebView
- QWebViewExample.pro - профайл проекта;
- main.cpp - основной файл исходных кодов проекта;
- mainwindow.h - заголовочный файл главного окна приложения;
- mainwindow.cpp - файл исходных кодов главного окна приложения;
- mainwindow.ui - форма главного окна приложения.
- 1. Структура проекта для работы с QWebView
- 2. QWebViewExample.pro
- 3. mainwindow.h
- 4. mainwindow.cpp
- 5. Исправление ошибок с SSL
- 6. Итог
- 7. Видеоурок
QWebViewExample.pro
Для работы с QWebView необходимо подключить два модуля: webkit и webkitwidgets.
mainwindow.h
В заголовочном файле необходимо объявить два слота:
slotEnter() - для обработки нажатия клавиши Enter в адресной строки браузера;
slotLinkClicked(QUrl url) - для обработки клика по ссылке на странице браузера.
Также необходимо подключить библиотеки QWebView и QUrl.
mainwindow.cpp
Для правильной обработки клика по ссылке необходимо установить ручную обработку данного события методом setLinkDelegationPolicy и подключить соответствующий слот к сигналу linkClicked().
Исправление ошибок с SSL
Скорее всего у Вас возникнут ошибки следующего вида при сборке проекта:
Решение этой проблемы кроется в том, чтобы подбросить нужные библиотеки в папку, где располагаются библиотеки Qt5Network.dll и Qt5Networkd.dll. Этими библиотеками являются libeay32.dll и ssleay32.dll.
- Идём на следующий сайт
- Ищем там light сборку OpenSSL
- И качаем нужную версию 32 или 64 бита (в случае с mingw качаем 32-х разрядную сборку).
- Далее устанавливаем OpenSSL в производную папку отметив пункт "The OpenSSL binaries (\bin) directory"
- После чего ищем библиотеки libeay32.dll и ssleay32.dll и перебрасываем их в папку с Qt к библиотекам Qt5Network.dll и Qt5Networkd.dll.
После этого выше перечисленные ошибки пропадут.
В результате проделанной работы Вы сможете открыть страницу сайта в своём собственном приложении, как показано на ниже следующем рисунке. Также демонстрацию работы приложения из урока Вы можете увидеть в Видеоуроке.
Ссылка на скачивание проекта в zip-архиве: qwebviewexample.zip
Видеоурок
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Интересная особенность пришла в Qt 5.10, это новый бэк-энд Qt, который использует WebGL для визуализации. Это позволяет приложениям Qt (с некоторыми ограничениями) работать в веб-браузере, который поддерживает WebGL.
Что это такое?
В новом бэк-энде используется WebGL, что означает Web Graphic Library . WebGL - это API JavaScript для визуализации 2D и 3D-графики в любом совместимом веб-браузере без использования плагинов. API похож на OpenGL ES 2.0 и может использоваться в элементах canvas HTML5.
Новый бэк-энд будет представлен как техническая функция предварительного просмотра в Qt 5.10.0 и включен в версии Alpha и Beta (на данный момент, Qt 5.10.0 является бета-версией на 1ом этапе разработки).
Плагин распространяется либо по лицензии GPLv3, либо по коммерческим лицензиям. Обратите внимание, что он недоступен в LGPL. Одним из последствий лицензии GPL является то, что если вы ссылаетесь на нее (даже динамически), код вашего приложения попадает под GPL.
- 1. Что это такое?
- 2. Как это использовать
- 3. Ограничения
- 4. Опыт
- 5. Заключение
- 6. Ссылки
Как это использовать
Плагин устанавливается в QTDIR /plugins/platforms/libqwebgl.so (в Windows путь аналогичен).
Ограничения
С выпусками Alpha и Beta 1 Qt 5.10.0 плагин WebGL успешно работал в системе Ubuntu Linux 17.04 с использованием браузера Chromium.
Плагин поддерживает только приложения QML. Неизвестно, будет ли он поддерживать виджеты. По словам разработчиков, поддержку виджетов будет трудно достичь с хорошей производительностью, потому что они полагаются на растеризацию.
Вы можете подумать, что запуск в браузере означает, что приложение будет работать в песочнице и не иметь доступа к каким-либо ресурсам за пределами браузера, например файлам. Однако в браузере выполняется только рендеринг, а само приложение работает как обычное приложение (однако оно может не работать на том же компьютере, что и на дисплее).
С Qt 5.10.0 Beta 1 несколько примеров QML, которые были пробованы, работали достаточно хорошо. Некоторые из них столкнулись с некоторыми проблемами, а некоторые не запускались вообще. Вот скриншоты из нескольких примеров.
Qt Quick Controls Text Editor:
Qt Quick Controls Gallery:
QML Photoviewer:
SameGame:
Заключение
В прошлом решение о разработке приложения, которое может запускаться нативно или в веб-браузере, обычно подразумевало использование значительно отличающихся стратегий (например, использование Qt/QML или использование HTML5). Предполагая, что плагин WebGL становится стабильным и завершенным, он предложит привлекательный подход для разработки веб-приложений используя Qt и для превращения нативного приложения Qt на базе QML в веб-приложение с минимальными усилиями. Тем не менее, имейте в виду последствия лицензирования, когда вы решаете, использовать ли коммерческую или версию с открытым исходным кодом Qt.
Я с нетерпением жду, когда плагин WebGL будет задокументирован и станет более завершенным в выпуске Qt 5.10.0 в конце этого года
Ссылки
Статья написана: Jeff Tranter | Среда, Октябрь 25, 2017г.
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Well, who among us does not want to write your browser? Come on, do not deny it thought about the browser exactly were. So, the Qt has QWebView class that allows you to work with webkit browser engine, which is written chromium, and, accordingly, chrome and many other browsers. Therefore, practical use of a dozen lines of code, you can make an application that can display a page of the website.
Thus, the application will be as follows. There is an address bar QLineEdit and a widget QWebView . When you enter a website address in the address bar and pressing Enter key will start getting the site and display it in QWebView . When you click on the link in the link address will be displayed in the address bar and a new page will be loaded in the widget.
Project structure for work with QWebView
- QWebViewExample.pro - the profile of the project;
- main.cpp - the main project source code file;
- mainwindow.h - header file of the main application window;
- mainwindow.cpp - file source code of the main application window;
- mainwindow.ui - form the main application window.
- 1. Project structure for work with QWebView
- 2. QWebViewExample.pro
- 3. mainwindow.h
- 4. mainwindow.cpp
- 5. Correction of errors with SSL
- 6. Result
- 7. Video
QWebViewExample.pro
To work with QWebView need to connect two modules: webkit and webkitwidgets .
mainwindow.h
The header must declare two slots:
slotEnter() - for the handling of pressing the Enter key in the browser address bar;
slotLinkClicked(QUrl url) - to handle a click on a link on the browser page.
Также необходимо подключить библиотеки QWebView и QUrl.
mainwindow.cpp
For handling correctlry of a click on the link you need to install the manual processing of the event by setLinkDelegationPolicy and connect the appropriate slot to the signal linkClickek().
Correction of errors with SSL
Chances are you have an error that resembles the following when you build the project:
The solution to this problem lies in the fact, to throw the necessary libraries to the folder where are Qt5Network.dll and Qt5Networkd.dll library. These libraries are libeay32.dll and ssleay32.dll .
- Go to the following site
- We are looking for light build of OpenSSL
- And shakes the required version of 32 or 64 bits (in the case of mingw swing 32-bit assembly).
- Next install OpenSSL in derivative folder item noting "The OpenSSL binaries (\ bin) directory"
- Then we look for the libraries libeay32.dll and ssleay32.dll and we move them to a folder with the Qt libraries Qt5Network.dll and Qt5Networkd.dll.
Result
As a result of the work done, you can open a page of the site in its own application, as shown in the following figure.
Link to the project download in zip-archive: qwebviewexample.zip
Video
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
В процессе разработки приложения на Qt, может понадобиться добавить в данное приложение веб-интерфейс, что особенно может быть актуально при разработке встраиваемых систем с использованием Qt. Для решения данной задачи можно либо написать собственное решение, либо воспользоваться готовыми решениями. Например, библиотекой QtWebApp, которая предоставляет необходимый функционал для создания web-интерфейса.
- формирование страниц с динамическим содержанием по шаблонам;
- формирование полностью динамических страниц;
- работу с Cookie, что позволит добавить авторизацию на приложении;
- работу со статическими файлами, например, style.css или изображения;
- реализацию загрузки файлов.
На момент написания статьи изначально использовалась библиотека QtWebApp 1.6.3 и Qt 5.6. Проект успешно был запущен с комплектами сборки MSVC2013 и MinGW. В процессе отладки был замечен баг в классе Template библиотеки QtWebApp. После исправления бага и связи с разработчиком версия библиотеки была повышена до 1.6.4. Исходя из этого, можно отметить также плюс библиотеки, что разработчик ответил в течение суток на информацию о баге, и в тот же день версия библиотеки была повышена. Окончательный вариант примера приложения был подготовлен на версии 1.6.4.
В данном проекте предлагается создать приложение, имеющее три страницы, меню для выбора этих страниц, и три статических файл. Один из файлов – это style.css, а два других – это изображения.
Структура проекта
Проект будет сформирован в виде Subdirs проекта, который будет состоять из основного проекта и проекта библиотеки QtWebApp.
Структура проекта:
QtWebAppExample.pro – основной профайл проекта
common – пользовательский проект web-сервера
QtWebAppExample.pro
Общий профайл проекта — шаблон subdirs с подключённым основным проектом и библиотекой QtWebApp. Важна последовательность подключения проектов в файле. Библиотека QtWebApp должна быть прописана первой, иначе при сборке проекта возникнут ошибки:
если на момент сборки основного проекта, который зависит от QtWebApp, собранных файлов библиотеки (.dll или .so) не будет в наличии, проект не соберется.
common.pro
Помимо этого, необходимо правильно прописать линковку к заголовочным файлам и файлам исходных кодов, а также выходные папки для сборки библиотеки, чтобы собираемый проект смог обратиться по правильному пути к файлам библиотеки.
QtWebApp.pro
Профайл проекта библиотеки по умолчанию показан ниже. Единственным изменением в проекте стало наличие дополнительной настройки сборки в качестве статической библиотеки.
main.cpp
А теперь по порядку пройдёмся по всем файлам проекта common, чтобы разобраться, как можно запустить Qt-приложение с web-интерфейсом. Начнём со стартового файла приложения и с функции main, с которой осуществляется запуск приложения.
Здесь имеется получение пути к файлу настроек, в котором хранятся параметры настройки web-сервера, порт TCP/IP и т.д.
Также создаётся объект класса WebConfigurator, который отвечает за обработку запросов и выдачу по запросам соответствующих страниц web-сервера.
Содержит фактически вспомогательный класс, не несущий в себе сверх необходимой информации, но в него для удобства вынесена инициализация файла настроек и в случае более глобального проекта данный класс будет удобно расширить. В данном варианте, естественно, больше похоже на дело вкуса.
Все параметры относятся к настройке порта подключения, количеству одновременных сессий, длительности ожидания запроса.
Также в настройках приложения будут содержаться и параметры контроллера статических файлов, в частности путь к папке, в которой будет производиться поиск статических файлов веб-сервера. В данном приложении это папка html-static, которая будет располагаться в той же папке, что и исполняемый файл приложения.
WebConfigurator.h
А теперь внимательно посмотрим на содержимое класса WebConfigurator, который отвечает непосредственно за определение страниц, которые подлежат к отправке на запрос извне.
Определение страниц осуществляется с помощью объекта класса QHash, который содержит указатели на все объекты web-страниц и соответствующие им ключевые значения, которые соответствуют URL адресам запросов. Но QHash используется лишь для динамических страниц, а для статических страниц используется объект класса StaticFileController.
Webconfigurator.cpp
WebConfiguratorPage.h
Данный заголовочный файл содержит объявление основного класса, отвечающего за формирование страниц и наследованные от него три класса страниц для проекта: index.html, first.html, second.html.
WebConfiguratorPage.cpp
Common.htm
Под занавес рассмотрим содержимое шаблонов.
index.htm
Результат
В итоге получим рабочее приложение с веб-сервером, который отлично подойдет для встраиваемых систем.
А данное приложение сформирует следующую веб-страницу.
Примечание
Проект приложения можно скачать по ссылке: скачать.
При сборке проекта обязательно поставьте этап install, чтобы необходимые статические файлы были установлены в соответствующую папку к исполняемому файлу.
Немного о баге
Добавим пару слов о баге, который сам по себе был больше похож на результат неудачного рефакторинга кода или, скорее, разработчик просто был в определенный момент уставший. Дело в том, что в более ранних версиях QtWebApp, а именно в версии 1.5.10, код был корректным и выглядел следующим образом.
Тогда как в версии 1.6.3 была пропущена одна единственная строчка.
В результате данные не добавлялись в шаблон страницы, и пользователь получал пустую страничку. Как сообщил Стефан Фрингс, разработчик QtWebApp, он обычно использует иной, нежели мы, подход к формированию веб-интерфейса, поэтому просто не замечал подобной проблемы.
Читайте также: