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
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
To copy to clipboard, switch view to plain text mode
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
MainWindow w;
w.show();
return a.exec();
}
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
To copy to clipboard, switch view to plain text mode
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
{
Q_OBJECT
public:
MainWindow
(QWidget *parent
= nullptr
);
~MainWindow();
private:
void setupUi();
Ui::MainWindow *ui;
};
#endif // 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
To copy to clipboard, switch view to plain text mode
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQuickWidget>
#include <QQmlError>
#include <QQmlEngine>
#include <QHBoxLayout>
MainWindow
::MainWindow(QWidget *parent
) , ui(new Ui::MainWindow)
{
setupUi();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupUi()
{
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();
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
if( !QFile::exists(path
) ) { return;
}
return;
}
scriptFile.close();
engine->evaluate(result);
functionResult = engine->evaluate("getLabel()");
qDebug() << functionResult.toString();
}
#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();
}
To copy to clipboard, switch view to plain text mode
qml.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
To copy to clipboard, switch view to plain text mode
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()
}
}
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()
}
}
To copy to clipboard, switch view to plain text mode
Bookmarks