PDA

View Full Version : How to evaluate inline function in .qml file



donelron
14th September 2021, 09:58
Dear all,

I have a C++ application that dynamically reads a .qml file and and uses it to create a QQuickWidget. Inside my .qml there is a function "getLabel()" that is used for the creation of the UI element. However, I also need to call this function from C++ code directly. Unfortunately, I am running out of ideas on how to acomplish that. I am convinced that the QQmlEngine of the QQuickWidget that I use must know the function "getLabel()" from the .qml file because it is called in order to set the text property of the label. So, how can I acces this function from C++?
I have attached a minimal working example to show what I have done so far:

QMLtest.pro


QT += core gui quickwidgets qml quick

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
main.cpp \
mainwindow.cpp

HEADERS += \
mainwindow.h

RESOURCES += qml.qrc

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target



main.cpp


#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}



mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

private:
void setupUi();

Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H




mainwindow.cpp


#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QQuickWidget>
#include <QQmlError>
#include <QQmlEngine>

#include <QHBoxLayout>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
setupUi();
}

MainWindow::~MainWindow()
{
delete ui;
}


void MainWindow::setupUi()
{
QWidget* mainWidget = new QWidget(this);
QHBoxLayout* layout = new QHBoxLayout(mainWidget);

QQuickWidget* quickWidget = new QQuickWidget(mainWidget);
layout->addWidget(quickWidget);
quickWidget->setSource(QUrl::fromLocalFile(":/main.qml"));
foreach(QQmlError err, quickWidget->errors()) {
qDebug() << err.toString() << "\n";
qDebug() << err.url() << "\n";
qDebug() << err.description() << "\n";
qDebug() << err.line() << "\n";
}

setCentralWidget(mainWidget);

QQmlEngine* engine = quickWidget->engine();


engine->dumpObjectInfo();
engine->dumpObjectTree();


QJSValue gobalObject = engine->globalObject();
qDebug() << gobalObject.hasProperty("getLabel()");
qDebug() << gobalObject.hasProperty("Rectangle");
qDebug() << gobalObject.hasProperty("rectangleMain");
qDebug() << gobalObject.hasOwnProperty("getLabel()");
qDebug() << gobalObject.hasOwnProperty("Rectangle");
qDebug() << gobalObject.hasOwnProperty("rectangleMain");


//QQmlContext *QQmlEngine::rootContext() const

QList<QByteArray> propNames = engine->dynamicPropertyNames();
foreach( QByteArray ba, propNames ) {
qDebug() << ba;
}


QJSValue functionResult = engine->evaluate("getLabel()");
qDebug() << functionResult.toString();


functionResult = engine->evaluate("Rectangle.getLabel()");
qDebug() << functionResult.toString();

functionResult = engine->evaluate("rectangleMain.getLabel()");
qDebug() << functionResult.toString();



QJSEngine* jsEngine = qobject_cast<QJSEngine*>(engine);
if( !jsEngine ) {
return;
}

functionResult = jsEngine->evaluate("getLabel()");
qDebug() << functionResult.toString();


functionResult = jsEngine->evaluate("Rectangle.getLabel()");
qDebug() << functionResult.toString();

functionResult = jsEngine->evaluate("rectangleMain.getLabel()");
qDebug() << functionResult.toString();

//Read the qml file
QString path = ":/main.qml";
if( !QFile::exists(path) ) {
return;
}
QFile scriptFile(path);
if (!scriptFile.open(QIODevice::ReadOnly)) {
return;
}
QTextStream stream(&scriptFile);
QString result = stream.readAll();
scriptFile.close();


engine->evaluate(result);
functionResult = engine->evaluate("getLabel()");
qDebug() << functionResult.toString();
}



qml.qrc


<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>


main.qml


import QtQuick 2.12
//import QtQuick.Window 2.12
//import Qt.labs.qmlmodels 1.0
import QtQuick.Controls 2.15

Rectangle {
id: rectangleMain
width: 500
height: 500
visible: true

function getLabel() {
return "hello world!";
}

Label {
text: getLabel()
}

}