Я резюмирую ваши вопросы следующим образом:
- Нужен ли QWebChannel для регистрации функций JavaScript в WebEngine?
- Где я могу найти QWebChannel.js
- Как связать JS с C++ и C++ с JS
Во-первых, давайте возьмем простой код для игры:
#include <QApplication>
#include <QDebug>
#include <QWebEngineView>
#include <QWebChannel>
// ... DEFINITIONS HERE
auto main( int argn, char* argv[] )-> int
{
QApplication app(argn, argv);
QWebEngineView browser;
browser.resize(QSize(800,600));
browser.show();
browser.load(QUrl("http://www.wikipedia.org"));
// .. SETUP HERE
QObject::connect(&browser, &QWebEngineView::loadFinished, [&browser](bool ok)
{
qDebug()<<"Load Finished " << ok;
// TEST CODE HERE
));
return app.exec();
}
Объяснение: Этот код создает приложение Qt, создает QWebEngineView и устанавливает некоторые минимальные свойства, чтобы сделать его видимым. Страница из «Википедии» load
ed внутри, и событие signal/slot подключается для печати некоторого журнала, когда страница наконец загружена.
Как вызывать JS-функции из C++?
Вы можете просто вызвать JS, используя QWebEnginePage::runJavaScript
следующим образом. Добавьте этот код в файл TEST CODE HERE
.
QString code = QStringLiteral(
R"DELIM(
var links = document.getElementsByTagName('a');
for ( var i=0; i<links.length; ++i)
{
links[i].style.backgroundColor = 'yellow';
};
)DELIM");
browser.page()->runJavaScript(code, 42);
Объяснение: Этот код выполняет некоторые JS в браузере с идентификатором контекста 42
, избегая конфликта с контекстом по умолчанию для страницы с идентификатором 0
. Скрипт изменяет цвет фона каждой ссылки на желтый.
Как вызвать C++ из JS?
В этом случае нам нужен механизм QWebChannel для регистрации объектов C++ в JavaScript.
Во-первых, давайте создадим интерфейс C++, вызываемый из JS (в DEFINITION
):
class JsInterface: public QObject
{
Q_OBJECT
public:
/// Log, for debugging
Q_INVOKABLE void log(const QString& str) const
{
qDebug() << "LOG from JS: " << str;
}
};
#include "main.moc"
Объяснение: Этот код объявляет и определяет класс QObject с простой функцией log
внутри. Важно объявить функцию Q_INVOKABLE
, иначе JavaScript не сможет ее найти!. Поскольку объявление находится внутри того же файла, что и остальной код, мы включаем файл auto-moc из QT после (это main.moc
, потому что мой файл main.cpp
).
Создайте функцию в DEFINITION
, которая возвращает содержимое JavaScript QWebChannel.js
. Содержимое QWebChannel.js можно найти в вашей библиотеке QT (./5.12.2/Src/qtwebchannel/examples/webchannel/shared/qwebchannel.js или ./Examples/Qt-5.12.2/webchannel/shared/qwebchannel. js). Вы можете загрузить это прямо на своей странице.
В разделе DECLARATION
добавить:
QString qWebChannelJs()
{
return R"DELIMITER(
// COPY HERE ALL THE FILE
)DELIMITER";
}
И мы внедряем его в наш код (добавляем в раздел TEST CODE HERE
):
browser.page()->runJavaScript(qWebChannelJs(), 42);
Нам нужно настроить QWebChannel
на стороне C++ (раздел SETUP
):
QWebChannel channel;
JsInterface jsInterface;
browser.page()->setWebChannel(&channel, 42);
channel.registerObject(QString("JsInterface"), &jsInterface);
Объяснение: Мы создаем канал, объект JsInterface
и регистрируем их в браузере. Нам нужно использовать тот же идентификатор контекста 42
(но может быть и другое число от 0 до 255).
Наконец, в нашем JS-коде мы получаем доступ к каналу и вызываем функцию интерфейса (добавляем к секции TEST CODE
):
QString code2 = QStringLiteral(
R"DELIM(
window.webChannel = new QWebChannel(qt.webChannelTransport, function( channel)
{
var cpp = channel.objects.JsInterface;
cpp.log("Hello from JavaScript");
});
)DELIM");
browser.page()->runJavaScript(code2, 42);
Соображения
Стоит отметить, что любой вызов из C++ в JavaScript или из JavaScript в C++ проходит через Inter-Process-Communication (IPC), который является асинхронным. Это означает, что runJavaScript
возвращается до выполнения JavaScript и что JavaScript возвращается до выполнения C++ log
.
Полный код
#include <QApplication>
#include <QDebug>
#include <QWebEngineView>
#include <QWebChannel>
QString qWebChannelJs()
{
return R"DELIMITER(
// TODO INSERT JS code here
)DELIMITER";
}
class JsInterface: public QObject
{
Q_OBJECT
public:
/// Log, for debugging
Q_INVOKABLE void log(const QString& str) const
{
qDebug() << "LOG from JS: " << str;
}
};
#include "main.moc"
auto main( int argn, char* argv[] )-> int
{
QApplication app(argn, argv);
QWebEngineView browser;
browser.resize(QSize(800,600));
browser.show();
browser.load(QUrl("http://www.wikipedia.org"));
// .. SETUP HERE
QWebChannel channel;
JsInterface jsInterface;
browser.page()->setWebChannel(&channel, 42);
channel.registerObject(QString("JsInterface"), &jsInterface);
QObject::connect(&browser, &QWebEngineView::loadFinished, [&browser](bool ok)
{
qDebug()<<"Load Finished " << ok;
// TEST CODE HERE
QString code = QStringLiteral(
R"DELIM(
var links = document.getElementsByTagName('a');
for ( var i=0; i<links.length; ++i)
{
links[i].style.backgroundColor = 'yellow';
};
)DELIM");
browser.page()->runJavaScript(code, 42);
browser.page()->runJavaScript(qWebChannelJs(), 42);
QString code2 = QStringLiteral(
R"DELIM(
window.webChannel = new QWebChannel(qt.webChannelTransport, function( channel)
{
var cpp = channel.objects.JsInterface;
cpp.log("Hello from JavaScript");
});
)DELIM");
browser.page()->runJavaScript(code2, 42);
});
return app.exec();
}
Похожие темы:
Как настроить QWebChannel JS API для использования в QWebEngineView?
Внешняя документация:
https://doc.qt.io/qt-5/qwebengineview.html
https://doc.qt.io/qt-5/qwebchannel.html
https://doc.qt.io/qt-5/qtwebengine-webenginewidgets-contentmanipulation-example.html
person
Adrian Maire
schedule
05.06.2020