Accesing QML element from C++ code in QT - c++

I am trying to use QML with C++ in QT, but for now unsuccessfully. I cannot access my QML element from the C++ code using rootObjects() function. What am I doing wrong?
qml part:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: window
visible: true
width: 640
height: 520
title: qsTr("My app")
Item {
anchors.fill: parent
Rectangle {
id: rectangle1
x: 0
y: 0
width: 640
height: 370
color: "#ffffff"
}
Button {
id: startButton
x: 325
y: 425
text: qsTr("Start")
}
}
}
C++ Part:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
QObject *rootObject = engine.rootObjects().first();
qDebug() << rootObject->objectName();//prints ""
QObject *qmlObject = rootObject->findChild<QObject*>("window");// or "startButton"
//qDebug() << qmlObject->objectName(); //app fails, because window was not found
QList<QObject *> allQObjects = rootObject->findChildren<QObject *>();
for(int i=0;i< allQObjects.length();++i)
{
qDebug() << allQObjects[i]->objectName(); //prints everytime ""
}
qDebug() << "len: " << allPQObjects.length(); //prints 132
return app.exec();
}

At first: If you do not set a object name there will be no!
QML:
Rectangle { id : frame; objectName : "objFrame" color : "blue" }
Qt:
QObject *pRootObject = m_pQmlView->rootObject();
QObject *pobjFrame = m_pRootObject->findChild<QObject *>("objFrame");
The other way arround:
Qt:
m_pQmlView->rootContext()->setContextProperty( "_view", this );
QML:
Component.onCompleted: {
/********************** Connections ***************************/
// connect signal MyView::retranslate() with slot retranslate
_view.retranslate.connect(retranslate)
}

Need to add objectname to QML
ApplicationWindow {
id: window
objectName: "window"
...
}

Related

Interaction with qml objects from C++ code

I am trying to interact with an qml object from C++ file using QtQuick. But unfortunatelly unsuccessfully for now. Any idea what Im doing wrong? I tried 2 ways how to do it, result of the first was that findChild() returned nullptr, and in second try I am getting Qml comnponent is not ready error. What is the proper way to do it?
main:
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
// 1-st attempt how to do it - Nothing Found
QObject *object = engine.rootObjects()[0];
QObject *mrect = object->findChild<QObject*>("mrect");
if (mrect)
qDebug("found");
else
qDebug("Nothing found");
//2-nd attempt - QQmlComponent: Component is not ready
QQmlComponent component(&engine, "Page1Form.ui.qml");
QObject *object2 = component.create();
qDebug() << "Property value:" << QQmlProperty::read(object, "mwidth").toInt();
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
Page1 {
}
Page {
}
}
}
Page1.qml:
import QtQuick 2.7
Page1Form {
...
}
Page1.Form.ui.qml
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
Item {
property alias mrect: mrect
property alias mwidth: mrect.width
Rectangle
{
id: mrect
x: 10
y: 20
height: 10
width: 10
}
}
findChild takes object name as first parameter. But not ID.
http://doc.qt.io/qt-5/qobject.html#findChild.
Here in your code, you are trying to query with id mrect. So it may not work.
Add objectName in your QML and then try accessing with findChild using object name.
Something like below (I did not try it. So chances of compile time errors):
Add objectName in QML
Rectangle
{
id: mrect
objectName: "mRectangle"
x: 10
y: 20
height: 10
width: 10
}
And then your findChild as shown below
QObject *mrect = object->findChild<QObject*>("mRectangle");

Access to existing QML component from C++

I am a newbie in QML, and cannot resolve a simple issue. I want to get access to the QML components from C++, but I cannot.
The pointer test is always 0. What can be the reason?
The code is the following:
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication &app=reg6::Bonder::BonderGuiApplication::instance();
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QObject* test=engine.rootObjects().first()->findChild<QObject*> ("cameraArea");
test->setProperty("color","black");
return app.exec();
}
main.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 1800
height: 900
SplitView
{
anchors.fill: parent
orientation: Qt.Vertical
SplitView {
Layout.fillHeight: true
SplitView {
orientation: Qt.Vertical
width:400
Layout.minimumWidth: 400
Layout.maximumWidth: 500
Camera {
id: cameraArea
height: 400
Layout.maximumHeight: 400
Layout.minimumHeight: 300
}
List {
id: listArea
}
}
Bonder {
id: mainArea
Layout.fillWidth: true
}
Properties {
id: propertiesArea
Layout.minimumWidth: 300
Layout.maximumWidth: 400
}
}
Error {
id: errorArea
Layout.minimumHeight: 100
height: 200
}
}
}
Camera.qml
import QtQuick 2.5
Rectangle {
color: "lightblue"
}
You have to set the objectName property also of the QML component to get a valid pointer to your QObject because T QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const needs the objectName not the ID

Changing QML object from C++ slot

I want to change object defined in QML from a slot in C++. In slot startButtonClicked() I start timer which every second calls slot getData(). How can I change the label defined in QML from C++ slot genData()? Now I am able to change in only from main.cpp
class LogicClass : public QObject
{
Q_OBJECT
public:
LogicClass();
~LogicClass();
public slots:
void startButtonClicked(const QVariant &v);
void getData();
};
main:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
class LogicClass logicClass;
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
QObject *rootObject = engine.rootObjects().first();
QObject *qmlObject = rootObject->findChild<QObject*>("startButton");
QObject::connect(qmlObject, SIGNAL(qmlSignal(QVariant)),&logicClass, SLOT(startButtonClicked(QVariant)));
return app.exec();
}
qml:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: window
objectName: "window"
visible: true
width: 640
height: 520
title: qsTr("MY app")
Button {
id: startButton
objectName: "startButton"
x: 25
text: qsTr("Start")
signal qmlSignal(var anObject)
MouseArea {
anchors.fill: parent
onClicked: startButton.qmlSignal(startButton)
}
}
Label {
objectName: "latitudeLabelValue"
id: latitudeLabelValue
y: 478
width: 50
text: qsTr("")
}
}
}
You have to use the setProperty method:
QObject *lblLatitute = rootObject->findChild<QObject*>("latitudeLabelValue");
lblLatitute->setProperty("text", "234.234");
But consider to use the model/view/delegate paradigm.
Passing a pointer to rootObject to LogicClass() can be a solution.
QObject *rootObject = engine.rootObjects().first();
class LogicClass logicClass(rootObject);
Save it as a aparameter of a class, and use it. this->rootObject->rootObject->findChild<QObject*>("latitudeLabelValue");
and then the setProperty() function.

QML XML list view not working

I'm new to QML. I cannot get these code working.
Model.qml
import QtQuick 1.1
XmlListModel {
source: "./test.xml"
query: "/tag1/tag2"
onSourceChanged: {
console.log("source changed:" + source)
reload()
}
XmlRole { name: "id"; query: "id/string()" }
XmlRole { name: "name"; query: "name/string()" }
}
View.qml
import QtQuick 1.1
ListView {
width: 200
}
TheDelegate.qml
import QtQuick 1.1
Rectangle {
width: parent.width
height: 20
Text {
text: id + ": " + name
}
}
Main.qml
import QtQuick 1.1
Item {
id: container
Model {
id: resultModel
objectName: "resultModel"
}
View {
id: resultView
model: resultModel
delegate: TheDelegate {}
}
}
And in my main.cpp:
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QDeclarativeView view;
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
view.setSource(QUrl::fromLocalFile("./TheMain.qml"));
view.show();
int rtnVal = app.exec();
return rtnVal;
}
When i run the project, it just shows nothing, no window displayed.
Thanks in advance.
EDIT:
I use the qmlviewer(4.8.4) to debug my qmls, and i get the warning:
TheDelegate.qml:18: ReferenceError: Can't find variable: name
But I have to name defined in the XmlRole.
You need to set Height as well for listview.
ListView {
width: 200
height: parent.height;
}

Calling C++ method in QML Error "Cannot Call Method 'x' of null"

I'm having some difficuly calling a method from a C++ class in QML. I keep getting a "Cannot call method 'x' of null" error. Here is my code:
QML:
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Window 2.0
import Jane 1.0
ApplicationWindow
{
property MainWindowModel m_Model
...
Button {
id: m_PluralizeButton
text: "Pluralize"
anchors.left: parent.left
anchors.leftMargin: 10
anchors.top: m_OutputRow.bottom
anchors.topMargin: 10
onClicked: m_OutputText.text = m_Model.getPluralization();
}
}
MainWindowModel.h
class MainWindowModel : public QObject
{
Q_OBJECT
public:
MainWindowModel();
~MainWindowModel() {}
Q_INVOKABLE QString getPluralization() const;
private:
};
MainWindoModel.cpp
MainWindowModel::MainWindowModel() :
QObject()
{
}
QString MainWindowModel::getPluralization() const
{
return "Test";
}
Main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Need to register types prior to loading the file.
qmlRegisterType<MainWindowModel>("Jane", 1, 0, "MainWindowModel");
QQmlApplicationEngine engine(QUrl("qrc:/root/QML/MainWindowView.qml"));
QObject* topLevel = engine.rootObjects().value(0);
QQuickWindow* win = qobject_cast<QQuickWindow*>(topLevel);
if (!win)
{
qWarning("Error: not a valid window.");
return -1;
}
win->show();
return a.exec();
}
Any help will be appreciated, thanks.
You need to create your MainWindowModel first.
QML:
import Jane 1.0
...
MainWindowModel {
id: m_Model;
}
Button {
...
onClicked: m_OutputText.text = m_Model.getPluralization();
}