QML/C++ getting info from QML in main.cpp - c++

I'm trying to get info from a new type -Cloud- instantiated in the example.qml from my main.cpp.
I have no error of compilation neither of execution. I have only my empty object cloud.
Here my cloud.h
#ifndef CLOUD_H
#define CLOUD_H
#include <QtQuick/QQuickPaintedItem>
#include <QColor>
class Cloud: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
Cloud(QObject *parent=0);
QString name() const;
void setName(const QString &name);
QColor color() const;
void setColor(const QColor &color);
private:
QString m_name;
QColor m_color;
};
#endif
Here my cloud.cpp
#include "cloud.h"
#include <QPainter>
Cloud::Cloud(QObject *parent)
:QObject(parent)
{
}
QString Cloud::name() const{
return m_name;
}
void Cloud::setName(const QString &name)
{
m_name = name;
}
QColor Cloud::color() const
{
return m_color;
}
void Cloud::setColor(const QColor &color)
{
m_color = color;
}
Here my main.cpp
#include "cloud.h"
#include <QtQuick/QQuickView>
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlRegisterType<Cloud>("Sky", 1,0,"Cloud");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/example.qml")));
QQmlComponent component(&engine, QUrl((QStringLiteral("qrc:/example.qml"))));
Cloud *cloud = qobject_cast<Cloud*>(component.create());
if(cloud){
qWarning() << "The cloud is "<< cloud->name();
}else{
qWarning() << "there is no cloud" <<cloud;
}
return app.exec();
}
And finally, here my example.qml
import QtQuick 2.0
import Sky 1.0
Item {
width: 300
height: 200
Item{
Cloud{
id:aCloud
name: "Cumulus"
}
}
}
I tried to solve my problem following those tutorials :
Defining QML types
Extending QML example
Thank you for your help :)

When you do component.create(); you are creating an Item which has Cloud as a child. If you want to get Cloud you should do something like:
QObject* myObject = component.create();
QQuickItem* item = qobject_cast<QQuickItem*>(myObject);
Cloud *cloud = item->findchild<Cloud*>();
EDITED: Updated with coyotte508 remarks.

Thanks to Coyotte508 and perencia I succedded to find what was wrong :
in my main.cpp I had a QApplication instead of a QGuiApplication

Related

Integrating QML and C++ for login purposes

I'm trying to create a simple login app, which will authenticate via Google Firebase. So far, I have the authentication code working fine.
Header file:
#ifndef AUTHHANDLER_H
#define AUTHHANDLER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
class AuthHandler : public QObject
{
Q_OBJECT
public:
explicit AuthHandler(QObject *parent = nullptr);
~AuthHandler();
void setAPIKey(const QString & apiKey);
void signUserUp(const QString & emailAddress, const QString & password);
void signUserIn(const QString & emailAddress, const QString & password);
public slots:
void networkReplyReadyRead();
void performAuthenticatedDatabaseCall();
signals:
void userSignedIn();
private:
void performPOST( const QString & url, const QJsonDocument & payload);
void parseResponse( const QByteArray & response);
QString m_apiKey;
QNetworkAccessManager * m_networkAccessManager;
QNetworkReply * m_networkReply;
QString m_idToken;
};
#endif // AUTHHANDLER_H
Authentication .cpp file
#include "authhandler.h"
#include <QDebug>
#include <QVariantMap>
#include <QNetworkRequest>
#include <QJsonObject>
AuthHandler::AuthHandler(QObject *parent)
: QObject{parent}
, m_apiKey( QString() )
{
m_networkAccessManager = new QNetworkAccessManager( this );
connect( this, &AuthHandler::userSignedIn, this, &AuthHandler::performAuthenticatedDatabaseCall );
}
AuthHandler::~AuthHandler()
{
m_networkAccessManager->deleteLater();
}
void AuthHandler::setAPIKey(const QString &apiKey)
{
m_apiKey = apiKey;
}
void AuthHandler::signUserUp(const QString &emailAddress, const QString &password)
{
QString signUpEndpoint = "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + m_apiKey;
QVariantMap variantPayload;
variantPayload["email"] = emailAddress;
variantPayload["password"] = password;
variantPayload["returnSecureToken"] = true;
QJsonDocument jsonPayload = QJsonDocument::fromVariant( variantPayload );
performPOST( signUpEndpoint, jsonPayload);
}
void AuthHandler::signUserIn(const QString &emailAddress, const QString &password)
{
QString signInEndpoint = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + m_apiKey;
QVariantMap variantPayload;
variantPayload["email"] = emailAddress;
variantPayload["password"] = password;
variantPayload["returnSecureToken"] = true;
QJsonDocument jsonPayload = QJsonDocument::fromVariant( variantPayload );
performPOST( signInEndpoint, jsonPayload);
}
main.cpp file
#include <QCoreApplication>
#include "authhandler.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
//QCoreApplication a(argc, argv);
// AuthHandler authHandler;
//authHandler.setAPIKey("AIzaSyB-nAN8OlgxHzXC5gpISkodjEZJ7IdSpgI");
// authHandler.signUserIn("user2#user.com", "password123!");
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
AuthHandler authHandler;
authHandler.setAPIKey("AIzaSyB-nAN8OlgxHzXC5gpISkodjEZJ7IdSpgI");
authHandler.signUserIn("user3#user.com", "password123!");
return app.exec();
}
As you can see, I'm currently hardcoding the values used in the SignUserIn function. These values are then updated in Firebase, and this is working. My question is, how do I make it so that the hard-coded values are input by an user in a qml file? I created a qml file with the required layout, but I'm having trouble setting it up so that the .cpp file function executes when a button is clicked in qml.
Make the method signUserIn a slot in the AuthHandler class
public slots:
void signUserIn(const QString & emailAddress, const QString & password);
Register your AuthHandler to the QML engine in main.cpp
qmlRegisterSingletonInstance("AuthHandler", 1, 0, "AuthHandler", &authHandler);
Import the AuthHandler in QML
import AuthHandler
Send the user credentials from QML to your handler
TextEdit {
id: user
text: "user"
}
TextEdit {
id: password
text: "password"
}
Button {
text: qsTr("Login");
onClicked: {
console.log("login: " + user.text + " password: " + password.text);
AuthHandler.signUserIn(user.text, password.text);
}
}

How to display data added via another class in C ++ to ListView, QML?

I need to present all the data in the QLinkedList container (this was given by the task). I created two classes, DataObject for my delegates in ListView, Glav for container with DataObject objects. I have a button on which I add data to the container (the addItem function in the Glav class). The data is added but not displayed in the ListView. How to display them? I tried it through signals, it didn't work.
Here is the complete code of the project.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QStringListModel>
#include <QQmlContext>
#include <QLinkedList>
#include <QQuickView>
#include <container.h>
#include <dataobject.h>
#include "glav.h"
//#include <container.cpp>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<tile::Glav>( "Tile", 1, 0, "DataItem", "interface" );
qmlRegisterType<tile::Glav>( "Tile", 1, 0, "Glav");
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.5
//import App 1.0
import Tile 1.0
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Scroll")
// Container {
// id: container
// }
Glav {
id: glav
}
Row {
id: buttons
spacing: 20
padding: 10
anchors.horizontalCenter: parent.horizontalCenter
RoundButton {
padding: 20
text: "add item"
onClicked: {
glav.addItem()
listView.currentIndex = -1
}
}
Connections{
target: myModelObjectWhichWasSetAsContextProperty
onRowsInserted: console.log("rows were inserted")
}
ScrollView {
anchors.fill: parent
anchors.topMargin: buttons.implicitHeight + 10
ListView {
id: listView
width: parent.width
model: glav.list
//required model
delegate: Text {
property var d
d: model.modelData.id
text: model.modelData.name
}
removeDisplaced: Transition {
NumberAnimation { properties: "x,y"; duration: 100; easing.type: Easing.InOutQuad }
}
}
}
}
dataobject.h
#ifndef DATAOBJECT_H
#define DATAOBJECT_H
#include <QObject>
namespace tile {
class DataObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY changed)
Q_PROPERTY(QString color READ color WRITE setColor NOTIFY changed)
Q_PROPERTY(int id READ id WRITE setId NOTIFY changed)
public:
explicit DataObject(QString name = "Wana", QString color = "red", int id = 1, QObject *parent = nullptr);
QString name();
void setName(const QString &name);
QString color();
void setColor(const QString &color);
int id() const;
void setId(int id);
signals:
void changed();
private:
QString m_name;
QString m_color;
int m_id;
};
}
#endif // DATAOBJECT_H
dataobject.cpp
#include "dataobject.h"
#include <QDebug>
namespace tile {
DataObject::DataObject(QString name, QString color, int id, QObject* parent) :
QObject(parent)
, m_name (name)
, m_color (color)
, m_id (id)
{
//new DataObject();
qDebug() << m_name;
//emit changed();
}
QString DataObject::name()
{
return m_name;
}
void DataObject::setName(const QString &name)
{
m_name = name;
qDebug() << m_name;
emit changed();
}
QString DataObject::color()
{
return m_color;
}
void DataObject::setColor(const QString &color)
{
m_color = color;
emit changed();
}
int DataObject::id() const
{
return m_id;
}
void DataObject::setId(int id)
{
m_id = id;
emit changed();
}
}
glav.h
#ifndef GLAV_H
#define GLAV_H
#include <QObject>
#include <QLinkedList>
namespace tile {
class Glav : public QObject
{
Q_OBJECT
Q_PROPERTY( QLinkedList<QObject *> list READ list CONSTANT )
public:
explicit Glav(QObject *parent = nullptr);
//QLinkedList<QObject *> list();
//void setList(const QLinkedList<QObject *> &list);
Q_INVOKABLE QLinkedList<QObject *> pollist();
Q_INVOKABLE void addItem();
// Q_INVOKABLE QVariant pol();
signals:
void changed();
private:
QLinkedList<QObject *> m_list;
QLinkedList<QObject *> list();
};
}
#endif // GLAV_H
glav.cpp
#include "glav.h"
#include "dataobject.h"
#include <QDebug>
#include <QAbstractListModel>
namespace tile {
Glav::Glav(QObject *parent) : QObject(parent)
{
QLinkedList<QObject *> dataList = {
new DataObject("Item 1", "red"),
new DataObject("Item 2", "green"),
new DataObject("Item 3", "blue"),
new DataObject("Item 9", "yellow")
};
m_list << dataList;
QVariant::fromValue(m_list);
}
QLinkedList<QObject *> Glav::list()
{
return m_list;
}
//void Glav::setList(const QLinkedList<QObject *> &list)
//{
// m_list = list;
//}
//QVariant Glav::pol(){
// QVariant re = QVariant::fromValue(m_list);
// return re;
//}
QLinkedList<QObject *> Glav::pollist()
{
//qDebug() << QVariant::fromValue(m_list);
//QLinkedList<QObject *> f = m_list;
//QVariant::fromValue(m_list);
//qDebug() <<m_list;
return m_list;
}
void Glav::addItem()
{
qDebug() << m_list.count();
m_list << new DataObject();
qDebug() << m_list.count();
emit changed();
}
}
Your Glav class has a changed() signal but it doesn't do anything because your list property is constant (Q_PROPERTY( QLinkedList<QObject *> list READ list CONSTANT ))
You should change it to this:
Q_PROPERTY(QLinkedList<QObject*> list READ list NOTIFY changed)
That way you can let the ListView know that the list has just been changed by emitting the changed() signal.
Also, it's better to name the signal in accordance with the property it corresponds to: listChanged.
More info on how Q_PROPERTY works in the official documentation: https://doc.qt.io/qt-5/properties.html

How is a QList of QString assigned to a list view?

I wrote this database front-end program with Qt and I used a C++ function to return the result of each query. However, I'm not able to assign the results to a list view.
MyObject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QString> val READ val WRITE setVal NOTIFY valChanged)
public:
void setVal(QList<QString>);
QList<QString> val() const;
explicit MyObject(QObject *parent = nullptr);
Q_INVOKABLE int registernew(int Sno=0, QString Name="NULL",long long PhoneNo=0, QString Country="NULL",QString State="NULL", QString District="NULL", int PhoneLine=0,long long Whatsapp = 0);
Q_INVOKABLE int querydistrict(QString);
signals:
void valChanged();
private:
QList<QString> m_val;
};
#endif // MYOBJECT_H
MyObject.cpp
.............. void MyObject::setVal(QList<QString> list)
{
if(list != m_val)
{
m_val = list;
emit valChanged();
}
}
QList<QString> MyObject::val() const
{
return m_val;
}....................
main.cpp
#include <QGuiApplication>
#include<QQmlApplicationEngine>
#include "myobject.h"
#include<QQuickView>
#include<QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
///delete later!!
qmlRegisterType<MyObject>("io.qt.examples.MyObject", 1, 0, "MyObject");
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
page2.ui.qml
ScrollView {
id: scrollView
anchors.rightMargin: 20
anchors.leftMargin: 20
anchors.bottomMargin: 40
anchors.topMargin: 200
anchors.fill: parent
ListView {
id: listView
model: myobject.val
delegate: ItemDelegate {
text: modelData
}
}
}
Where am i going wrong? The list is never updated with values when i run the program. It is always blank. But the variable m_val, when I return it in MyObject.cpp and use qDebug to output it, outputs relevant strings.
You should not use QList<QString> but QStringList as it is registered. On the other hand if you are going to establish the data from C ++ since you indicate that it is the result of a query then that Q_PROPERTY is not of being written in QML. Finally, although it is not an error, it is better to register the classes before creating the QXApplication.
myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList val READ val NOTIFY valChanged)
public:
explicit MyObject(QObject *parent = nullptr);
QStringList val() const;
void setVal(QStringList val);
// other methods
signals:
void valChanged(QStringList val);
private:
QStringList m_val;
};
#endif // MYOBJECT_H
myobject.cpp
#include "myobject.h"
// other methods
QStringList MyObject::val() const{
return m_val;
}
void MyObject::setVal(QStringList val)
{
if (m_val == val)
return;
m_val = val;
emit valChanged(m_val);
}
main.cpp
// ...
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
qmlRegisterType<MyObject>("io.qt.examples.MyObject", 1, 0, "MyObject");
QGuiApplication app(argc, argv);
// ...
So when you do your query you must pass the result to setVal:
setVal(your_QStringList);

How to delete QML window on closing signal (how to do it right)?

I have some problems with qt + qml: Sometimes I get segmentation fault trying to clear QQmlengine. And even if program doesn't crashes it has memory leaks. (sorry for my english). I think so because the larger qml file (many nested classes) the larger application process even after QQmlengine was deleted. So my question is what am I doing wrong in the code below?
//main.cpp
#include "qmlwindow.h"
#include <QApplication>
int QMLwindow::someValue = 0;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
QSharedPointer<QMLwindow> w0(new QMLwindow);
QSharedPointer<QMLwindow> w1(new QMLwindow);
QSharedPointer<QMLwindow> w2(new QMLwindow);
w0.data()->createWindow();
w0.data()->createWindow();
w1.data()->createWindow();
w2.data()->createWindow();
return a.exec();
}
 
//qmlwindow.h
#ifndef QMLWINDOW_H
#define QMLWINDOW_H
#include <QObject>
#include <QQmlComponent>
#include <QQuickWindow>
#include <QSharedPointer>
#include <QDebug>
#include <QQmlEngine>
#include <QQmlContext>
class QMLwindow : public QObject
{
Q_OBJECT
private:
QSharedPointer<QQmlEngine> engine;
QQmlComponent *component;
QObject *windowObj;
QQuickWindow *loginWindow;
QVariant count;
public:
static int someValue;
explicit QMLwindow(QObject *parent = 0);
~QMLwindow();
void createWindow();
signals:
public slots:
void deleteWindow(QQuickCloseEvent *event);
};
#endif // QMLWINDOW_H
 
//qmlwindow.cpp
#include "qmlwindow.h"
QMLwindow::QMLwindow(QObject *parent) : QObject(parent)
{
someValue++;
count = someValue;
qDebug() << "construction of QMLwindow " << count.toInt();
}
QMLwindow::~QMLwindow()
{
qDebug() << "destruction of QMLwindow " << count.toInt();
}
void QMLwindow::createWindow(){
if(engine.isNull()){
engine = QSharedPointer<QQmlEngine>(new QQmlEngine);
component = new QQmlComponent(engine.data());
component->loadUrl(QUrl(QStringLiteral("qrc:/SomeWindow.qml")));
Q_ASSERT(component->isReady());
windowObj = component->create();
loginWindow = qobject_cast<QQuickWindow *> (windowObj);
engine.data()->rootContext()->setContextProperty("someValue", count) ;
connect(loginWindow, SIGNAL(closing(QQuickCloseEvent*)), SLOT(deleteWindow(QQuickCloseEvent*)));
loginWindow->show();
}
else loginWindow->show();
}
void QMLwindow::deleteWindow(QQuickCloseEvent*event){
Q_UNUSED(event)
if(!engine.isNull()) {
qDebug() << "loginWindow destruction";
engine.clear();
}
this->deleteLater();
}
 
//SomeWindow.qml
import QtQuick 2.3
import QtQuick.Window 2.0
Window {
width: 200
height: 200
color: "white"
Text{
text: someValue
anchors.centerIn: parent
}
}

Qt C++ return string value

I have the following code:
filter.h
#pragma once
#include <QObject>
#include <QSortFilterProxyModel>
class FilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit FilterModel(QObject *parent = 0);
Q_INVOKABLE QString getText (QString text);
};
filter.cpp
#include "filter.h"
#include <QDebug>
FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent) {}
QString FilterModel::getText(QString text)
{
QString qmltext = text;
qmltext != NULL ? qDebug() << qmltext
: qDebug() << "TEXT = NULL";
return qmltext;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "abonentstable.h"
#include "filter.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
AbonentsSqlModel *abonentsSqlModel = new AbonentsSqlModel;
abonentsSqlModel->setQuery("SELECT * FROM abonents");
FilterModel *filterModel = new FilterModel;
filterModel->setSourceModel(abonentsSqlModel);
filterModel->setFilterKeyColumn(0);
filterModel->setFilterWildcard("9");
QQmlContext *context = engine.rootContext();
context->setContextProperty("abonents", filterModel);
context->setContextProperty("filter", filterModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
And the .qml file part:
TextField {
id: textField
...
onTextChanged: {
filter.getText(textField.text)
}
...
}
Method getText() gets text (suddenly!) from QML TextField and prints it into debugger, it works fine. But as you can see, I have code for table sorting.
The following problem is: now sorting mask is "9", it works, but I need to return QString qmltext from getText() in some way and put it into filterModel->setFilterWildcard() in main.cpp like that:
QString qmlText = filterModel.getText(QString);
...
filterModel->setFilterWildcard(qmlText);
Of course, it's just an example, it doesn't works and I don't know how to do this.
I do not fully understand what you want to do, but I think you need something like that (if you really need the return value):
QString FilterModel::getText(const QString& text)
{
setFilterWildcard(text);
return text;
}
By the way:
qmltext != NULL
is not working. Use instead:
qmltext.isEmpty() == false