https://habr.com/ru/post/481142/Данный пример построен на примере из книги
М.Шлее «Qt профессиональное программирование на Qt» «Черепашья графика». Для лучшего понимания работы советую почитать раздел «Язык сценариев Qt Scripts».
В примере будет реализован простой терминал, в который можно вводить команды. Результат выполнения команд будет отображаться в этом же терминале. Пользовательский интерфейс будет реализован на QML.
Создадим проект Qt Quick
Опишем форму. Файл main.qml:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.0
Window {
id: window
visible: true
width: Screen.width/2
height: Screen.height/2
title: qsTr("Тест jsEnjine")
property string consoleFontFamily: "Consolas"
property int fontPixelSize: 14
TextArea {
id: textAreaLog
anchors.bottom: rectangle.top
anchors.bottomMargin: 3
anchors.right: parent.right
anchors.rightMargin: 3
anchors.left: parent.left
anchors.leftMargin: 3
anchors.top: parent.top
anchors.topMargin: 3
readOnly: true
}
Rectangle {
id: rectangle
height: 25
anchors.right: parent.right
anchors.rightMargin: 3
anchors.left: parent.left
anchors.leftMargin: 3
anchors.bottom: parent.bottom
anchors.bottomMargin: 3
border.color: "#0c0a0a"
TextEdit {
id: textEditInput
anchors.right: parent.right
anchors.rightMargin: 5
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
font.pixelSize: fontPixelSize
}
}
}
Форма
Добавим в проект классы
AppCore и
Console, немного допишем
main.c
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "appcore.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
AppCore appCore;
QQmlApplicationEngine engine;
QQmlContext *context = engine.rootContext();//Создаем корневой контекст
//Загружаем объект в контекст для установки соединения, а
//так же определяем имя
//по которому будет происходить соединение
context->setContextProperty("appCore",&appCore);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if(engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
appcore.h
#ifndef APPCORE_H
#define APPCORE_H
#include <QObject>
#include <QJSEngine>
#include "console.h"
class AppCore : public QObject
{
Q_OBJECT
public:
explicit AppCore(QObject *parent = nullptr);
private:
QJSEngine appScriptEngine;
Console *userConsole;
signals:
Q_INVOKABLE void appEndTextArea(const QString& text);
Q_INVOKABLE void clearTextArea();
public slots:
Q_INVOKABLE void slotEvaluate(const QString& code);
};
#endif // APPCORE_H
appcore.c
#include "appcore.h"
AppCore::AppCore(QObject *parent) : QObject(parent)
{
userConsole = new Console(this);
QJSValue val = appScriptEngine.newQObject(userConsole);
appScriptEngine.globalObject().setProperty("console",val);
connect(userConsole, SIGNAL(appEndTextArea(QString)),this,SIGNAL(appEndTextArea(QString)));
connect(userConsole, SIGNAL(clearTextArea()),this,SIGNAL(clearTextArea()));
}
void AppCore::slotEvaluate(const QString& code)
{
QJSValue result = appScriptEngine.evaluate(code);
if(result.isError()){
QString er = QString("Ошибка в строке %1: %2").arg(result.property("lineNumber").toInt()).arg(result.toString());
emit appEndTextArea(er);
}
}
console.h
#ifndef CONSOLE_H
#define CONSOLE_H
#include <QObject>
class Console : public QObject
{
Q_OBJECT
public:
explicit Console(QObject *parent = nullptr);
Q_INVOKABLE void log(const QString& message);
Q_INVOKABLE void clear();
signals:
Q_INVOKABLE void appEndTextArea(const QString& text);
Q_INVOKABLE void clearTextArea();
};
#endif // CONSOLE_H
console.cpp
#include "console.h"
Console::Console(QObject *parent) : QObject(parent)
{
}
void Console::log(const QString& message)
{
emit appEndTextArea(message);
}
void Console::clear()
{
emit clearTextArea();
}
В конструкторе класса
AppCore мы добавили экземпляр класса
Console в
QJSEngine, так же мы определили что будем обращаться к методам этого класса через
«console»
QJSValue val = appScriptEngine.newQObject(userConsole);
appScriptEngine.globalObject().setProperty("console",val);
Сигнал
appEndTextArea(const QString& text) — добавление текста в
textAreaLog в
main.qml.
Сигнал
clearTextArea() — очистить область вывода текста
textAreaLog в
main.qml.
Слот
slotEvaluate(const QString& code) — выполнение js кода, введенного в
textEditInput в
main.qml.
Допишем в
main.qml обработчики сигналов:
Connections{
target: appCore
onAppEndTextArea:{
textAreaLog.cursorPosition = textAreaLog.length;
textAreaLog.append(text);
}
onClearTextArea:{
textAreaLog.cursorPosition=0;
textAreaLog.text = "";
}
}
Так же допишем в
textEditInput сигнал, вызова слота
void slotEvaluate(const QString& code):
TextEdit {
id: textEditInput
anchors.right: parent.right
anchors.rightMargin: 5
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
font.pixelSize: fontPixelSize
Keys.onReturnPressed:{
if(textEditInput.text == "")return;
appCore.slotEvaluate(text)
clear()
}
Keys.onEscapePressed: clear()
}
Теперь при вводе команды в
textEditInput и нажатии
Enter команда будет передана в
slotEvaluate в
AppCore. При нажатии ESC поле
textEditInput очистится.
При запуске приложения, если мы введем в
textEditInput команду console.log(«Hello world»), то в поле
textAreaLog увидим Hello world. Если ввести команду неизвестную
QJSEngine, то в терминале высветится ошибка.
Таким образом, мы написали приложение, в котором мы можем вызывать методы подключенных к QJSEngine классов и выводить результаты выполнения этих методов. Кто то скажет
«А при чем тут JS? Ведь классы написаны на С++?», но это уже другая история…
Ссылка проекта на github