Гибридное приложение Qt + Javascript

Safoyeth 5 Фев 2019

Данный эпос, как и было обещано в статье Гибридное приложение PyQt + React, будет посвящён разработке гибридного приложения на чистом Qt и чистом же (никаких React!) javascript. Используя эти две статьи вы сможете самостоятельно создавать любые приложения на Qt/PyQt и Js/React (да хоть на Angular!). В качестве бандлера также можно использовать что угодно. В статье про React я использовал parcel, но нет никаких ограничений на использование чего угодно. Мы же переходим к созданию проекта.

Я буду использовать Qt 5.11.2 с компилятором MSVC2017 64 bit. У меня нет цели выяснить что изменилось в Qt 5.12, поэтому я просто буду использовать свою текущую версию. Также сразу скажу, что MinGW не поддерживается! При попытке собрать проект этим компилятором вы получите ошибку Project ERROR: Unknown module(s) in QT: webengine webenginewidgets

Для начала создаём простой проект Qt Widgets. В качестве базового класса будем использовать . У меня в QtCreator 4.7.2 QWebEngineView нет, поэтому файл формы необходимо открыть в QtDesigner. В дизайнере нужно выбрать и сделать QWebEngineView виджет центральным. В результате получится примерно такая разметка:

Мы больше не будем трогать Ui. В файле .pro необходимо изменить строчку импортов так: QT += core gui webengine webenginewidgets. Теперь проект можно собрать и увидеть пустое окно с центральным виджетом QWebEngineView.

Создаём WebClass. Как обычно, он должен быть потомком QObject. В секции инклюдов в файле mainwindow.h подключаем <QWebChannel> и webclass.h. В секции private пишем:

Дальше в конструктор класса (в файл mainwindow.cpp после ui->setupUi(this);) пишем:

Всё, мы соединили WebClass (webobj) с html (с именем «server»)! Время написать сам html.

Сам html-файл будет элементарным до одури. Связано это с тем, что полностью рабочее приложение, которое что-то делает мы уже писали, сегодня же чисто обучающая статья. Итак, index.html:

Пара комментариев:

  • Мы снова подключаем firebug
  • qwebchannel.js снова подключается самым первым. Читайте Гибридное приложение PyQt + React чтобы узнать где взять этот файл, если у вас его нет
  • Все наши связи в этот раз будут реализованы в файле qtconnector.js
  • В этот раз я не буду использовать jquery

В остальном же html говорит сам за себя. Мы сразу пишем методы-заглушки типа onclick="window.server.method()". Осталось только связать html и Qt. Для начала наши файлы index.html, qwebchannel.js и qtconnector.js нужно положить в папку static. Саму же папку со всем содержимым нужно поместить в путь %ПУТЬ/ДО/СБОРКИ/debug/%. Если использовать систему ресурсов Qt, то у меня почему-то ничего не работало. Возможно что-то с моими мозгами, или же это баг. Как бы то ни было, мне приходится таскать папку со статикой ручками, иначе просто ничего не работает. Если у вас всё получится с помощью файлов ресурсов Qt, то вам легче. Теперь нужно уже соединить всё! В файле mainwindow.cpp в конструктор дописываем

Компилируем, запускаем и видим чудовищно медленную (отдельное спасибо firebug!) загрузку страницы! Почему всё работает так медленно — вопрос, но это так. Повторюсь ещё раз, я не делал тестов, но приложение PyQt стартует в разы быстрее (ну ладно, не в разы, но быстрее!), это видно даже не вооружённым глазом. Для меня загадка в чём же причина такой неспешности Qt, но сейчас это не так важно…

Пришло время проверить соединение между Qt и javascript. открываем файл qtconnector.js и пишем

Компилируем, запускаем и, если нигде не сделали ошибку, видим, что страница нам выдаёт alert с нашим текстом. Теперь пришло время реализовать четыре задачи, о которых мы написали ещё в html.

Вызов метода Qt из javascript

Мы пойдём от простого в сложному и начнём с самого элементарного, то есть с простого вызова метода Qt из javascript. Создадим метод calledFromJs()(да, не забудем подключить QMessageBox). Важно помнить, что у нас в html уже́ есть заглушка типа onclick="window.server.method()"

Компилируем, запускаем, нажимаем, получаем результат. Да, сто́ит напомнить, что метод в Qt должен называться также, как и в javascript!

Вызов метода Qt из javascript с аргументом

Не сложнее предыдущего. Опять же помним про то, что методы должны называться одинаково!

Скомпилировав, можно убедиться в работоспособности. Тут нам на помощь придёт сам Qt и если мы не укажем аргумент, то он автоматически выполнит преобразование из "" в 0, то есть toInt(). Дальше будет несколько сложнее.

Получение данных из Qt

Для начала создадим кнопку «Случайное число» и поместим её в toolbar:

Мы сразу связываем кнопку с сигналом value_changed в WebClass. Переходим в webclass.h и создаём наш сигнал:

Больше в Qt нам ничего создавать не нужно, теперь по нажатию на кнопку будет вызываться сигнал value_changed, который нам и нужно связать с javascript. Переходим к файлу qtconnector.js и после строчки window.server = server; пишем

Также нам необходимо реализовать updateattribute. Сделаем это в самом начале файла:

Мы просто находим элемент с id="value" и вставляем туда случайное значение, полученной из Qt. Компилируем, проверяем. Вместо того, чтобы определять updateattribute, можно использовать стрелочные функции, что мы сделаем в последнем нашем задании.

Полный круг

Банальная задача просто для того, чтобы увидеть как именно можно реализовать круговорот данных 🙂 В нашем html-файле есть заглушка onclick="window.server.factorial(document.getElementById('arg2').value)", которая даже если пользователь ничего не внёс, отработает как надо (несмотря на то, что в консоль вывалится сообщение Could not convert argument QJsonValue(string, "") to target type int .) — опять же благодаря встроенному в Qt toInt. Дальше, реализуем метод factorial и создадим сигнал factorial_changed

Тут всё относительно просто. Факториал определяется рекурсивно (и да, из-за того, что лямбда возвращает int он может быть определён только для нескольких первых значений), после чего выполняется вызов сигнала. Осталось реализовать связь сигнала в javascript. И да, в этот раз я использую стрелочную функцию!

Профит!

Прямой вызов javascript

Нам осталось ещё одна задача — прямой вызов javascript из Qt. Для этого сначала создадим ещё одну кнопку и добавим её на тулбар, после чего свяжем её с простым javascript alert.

Примерно то же самое мы делали в python.

Таким образом мы написали полностью рабочее (хоть и бесполезное) гибридное приложение Qt и Javascript. Я не буду повторяться про плюсы и минусы таких приложений, скажу лишь, что в данный момент связка Qt/JS проигрывает electron только в одном (на мой сугубо субъективный взгляд) — скорость запуска. В остальном же, qtwebengine — это просто огонь!

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.




Добавить комментарий

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: