Как стать автором
Обновить

Qt QJSEngine Hello world

Время на прочтение4 мин
Количество просмотров4.6K
Данный пример построен на примере из книги М.Шлее «Qt профессиональное программирование на Qt» «Черепашья графика». Для лучшего понимания работы советую почитать раздел «Язык сценариев Qt Scripts».

В примере будет реализован простой терминал, в который можно вводить команды. Результат выполнения команд будет отображаться в этом же терминале. Пользовательский интерфейс будет реализован на QML.

Создадим проект Qt Quick

image

Опишем форму. Файл 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
        }
    }
}

Форма

image

Добавим в проект классы 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, то в терминале высветится ошибка.

image

Таким образом, мы написали приложение, в котором мы можем вызывать методы подключенных к QJSEngine классов и выводить результаты выполнения этих методов. Кто то скажет «А при чем тут JS? Ведь классы написаны на С++?», но это уже другая история…

Ссылка проекта на github
Теги:
Хабы:
+3
Комментарии0

Публикации

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн