I need to know how to acess the members of struct from qlist in qml.
Currently i can acess only the members of struct in qml and i am also able to acess simple qlist i.e. Qlist made of qString.
But the problem starts when i try to acess the members of struct embedded in qlist.
I have created a struct (MyStruct) in c++ and can acscess it in Qml. I can also acess QList ( which is QStrinList).
But problem comes when i am trying to access QList. it gives me the error
qrc:/OrderBar.qml:26: TypeError: Cannot read property 'name1' of undefined
the Codes are
QML
Text{
//text: myModel2.mystr.name1 // this works
text: myModel2.lstr[0].name1
y: sensor.width + 5
font.family: "Helvetica"
font.pointSize: 10
anchors.horizontalCenter: parent.horizontalCenter
}
C++
test.h
#ifndef TEST_H
#define TEST_H
#include <QObject>
struct MyStruct {
Q_GADGET
// Q_OBJECT
int m_val;
public:
QString m_name1;
QString m_name2;
QString m_name3;
QString m_name4;
Q_PROPERTY(int val MEMBER m_val)
Q_PROPERTY(QString name1 MEMBER m_name1)
Q_PROPERTY(QString name2 MEMBER m_name2)
Q_PROPERTY(QString name3 MEMBER m_name3)
Q_PROPERTY(QString name4 MEMBER m_name4)
};
Q_DECLARE_METATYPE(MyStruct);
class test : public QObject
{
Q_OBJECT
Q_PROPERTY(MyStruct mystr READ getMyStruct
WRITE setMyStruct NOTIFY myStructChanged)
Q_PROPERTY(QList<MyStruct> lstr READ getLstr
WRITE setLstr NOTIFY lstrChanged)
public:
explicit test(QObject *parent = nullptr);
MyStruct strObj;
MyStruct getMyStruct() const
{
return strObj;
}
void setMyStruct(MyStruct val)
{
strObj = val;
emit myStructChanged();
}
QList<MyStruct> strList;
QList<MyStruct> getLstr() const
{
return strList;
}
void setLstr(QList<MyStruct> val)
{
strList = val;
emit lstrChanged();
}
signals:
void myStructChanged();
void lstrChanged();
public slots:
};
#endif // TEST_H
test.cpp
#include "test.h"
test::test(QObject *parent) : QObject(parent)
{
MyStruct l_value;
l_value.m_name1 = "b1";
l_value.m_name2 = "b2";
setMyStruct(l_value);
QList<MyStruct> l_strList;
l_strList.append(l_value);
setLstr(l_strList);
}
The codes are absolutely right. I found out that this is a bug in Qt older version. I tested the codes with QT 5.14 and it fully works.
Related
could you take a look and explain, what am I doing wrong in code below?
#ifndef BACKEND_H
#define BACKEND_H
#include <QObject>
#include <QDebug>
#include <QtQml>
class BackEnd : public QObject
{
Q_OBJECT
Q_PROPERTY(int player READ player WRITE player_change)
QML_ELEMENT
int player;
public:
explicit BackEnd(QObject *parent = nullptr);
signals:
int player_changed(int player);
public slots:
int player_change(int player);
};
#endif // BACKEND_H
cpp:
#include "backend.h"
BackEnd::BackEnd(QObject *parent)
: QObject{parent}
{
}
int BackEnd::player_change(int player)
{
return (player == 1) ? 2 : 1;
}
Error:
Expression cannot be used as a function
Error appears in auto-edited moc file...
Removing Q_PROPERTY makes it fine...
The error says that the Q_PROPERTY macro can't use the member player as a function.
A READ accessor function is required if no MEMBER variable was
specified. It is for reading the property value. Ideally, a const
function is used for this purpose, and it must return either the
property's type or a const reference to that type. e.g.,
QWidget::focus is a read-only property with READ function,
QWidget::hasFocus().
You need to create a getter and use it as the READ function. Or you use MEMBER.
A MEMBER variable association is required if no READ accessor function
is specified. This makes the given member variable readable and
writable without the need of creating READ and WRITE accessor
functions. It's still possible to use READ or WRITE accessor functions
in addition to MEMBER variable association (but not both), if you need
to control the variable access.
Have a look here.
#ifndef BACKEND_H
#define BACKEND_H
#include <QDebug>
#include <QObject>
#include <QtQml>
class BackEnd : public QObject
{
Q_OBJECT
Q_PROPERTY(int foo READ foo WRITE setFoo NOTIFY fooChanged)
Q_PROPERTY(int bar MEMBER bar NOTIFY barChanged)
QML_ELEMENT
public:
explicit BackEnd(QObject *parent = nullptr) : QObject{parent} {}
int foo() const { return m_foo; }
void setFoo(int val) { m_foo = val; emit fooChanged(); }
signals:
void fooChanged();
void barChanged();
private:
int m_foo;
int bar;
};
#endif // BACKEND_H
I'm trying to expose the QSerialPort.available() through an Q_INVOKABLE QStringList availablePorts() function from a class I expose directly to QML in my main class.
Main:
qmlRegisterType<SerialPortManager>("com.MyApp.qml", 1, 0, "SerialPortManager");
SerialPortManager
class SerialPortManager : public QObject
{
Q_OBJECT
public slots:
Q_INVOKABLE virtual QStringList availablePorts() {
QList<QSerialPortInfo> portsAvailable = QSerialPortInfo::availablePorts();
QStringList names_PortsAvailable;
for(QSerialPortInfo portInfo : portsAvailable) {
names_PortsAvailable.append(portInfo.portName());
}
return names_PortsAvailable;
}
Which is not valid for a model type in QML because it raises Unable to assign QStringList to QQmlListModel* error.
QML
ComboBox {
model: serial.availablePorts()
}
SerialPortManager {
id: serial
}
So how do I get around this?
One solution is to return a QVariant as recommended by the docs, for this we use QVariant::fromValue()
#ifndef SERIALPORTMANAGER_H
#define SERIALPORTMANAGER_H
#include <QObject>
#include <QSerialPortInfo>
#include <QVariant>
class SerialPortManager : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE static QVariant availablePorts() {
QList<QSerialPortInfo> portsAvailable = QSerialPortInfo::availablePorts();
QStringList names_PortsAvailable;
for(const QSerialPortInfo& portInfo : portsAvailable) {
names_PortsAvailable<<portInfo.portName();
}
return QVariant::fromValue(names_PortsAvailable);
}
};
#endif // SERIALPORTMANAGER_H
So I I have an h file and a cpp file in a Qt project. I have to declare some qstrings inside my header file and I would like to reference them in my cpp file but I don't seem to be able to access it, can someone explain why or the correct way to do it?
#ifndef PROFILE_H
#define PROFILE_H
#include <QMainWindow>
#include "login.h"
#include "searchnote.h"
#include "note.h"
#include <QDebug>
namespace Ui {
class Profile;
}
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
private slots:
void on_actionAdd_Note_triggered();
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
Note myNoteList;
};
#endif // PROFILE_H
#include "profile.h"
#include "ui_profile.h"
Profile::Profile(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Profile)
{
ui->setupUi(this);
}
Profile::~Profile()
{
delete ui;
}
void Profile::on_actionAdd_Note_triggered()
{
SearchNote openSearch; //will send us the searchNote gui
openSearch.setModal(true);
openSearch.exec();
}
void myNoteListAdd(QString newName){
myNoteList.add(); //the cpp file doesnt recognize this object
}
myNoteListAdd is a stand-alone function, myNoteList is a private data member of Profile class.
Only member functions (often also called methods) of the same class can access these private data members
It may be the case that you intend myNoteListAdd to be a member function of Profile, i.e.
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
private slots:
void on_actionAdd_Note_triggered();
**void myNoteListAdd(QString newName);**
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
Note myNoteList;
};
And implement as:
void Profile::myNoteListAdd(QString newName){
myNoteList.add(newName); // assuming you want to add newName to myNoteList
}
Otherwise, you need some form of accessing the member myNoteList, either by making it public or having a getter member. In either case you need an instance of a Profile to work with, i.e.:
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
//either this:
Note myPublicNoteList;
// or this
Note getNoteList() { return myNoteList; }
private slots:
void on_actionAdd_Note_triggered();
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
};
then in your .cpp
void myNoteListAdd(QString newName)
{
Profile p = new Profile(); // or some other mechanism to get a Profile
//then either
p.myPublicNoteList.add(newName);
// or
p->getNoteList().add(newName);
}
Hello I have a struct in a TreeItem class:
// TreeItem.h
class TreeItem
{
public:
struct TreePair
{
QString sa_key;
QVariant sa_value;
};
//... blabla
}
I would like access that struct TreePair from another class TreeModel , which has class TreeItem already formarded in its header:
// TreeModel.h
class TreeItem;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
//..
}
// TreeModel.cpp
TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent)
: QAbstractItemModel(parent)
{
QVector<TreePair> rootData; // TreePair was not declared in this scope
}
My strcut was not declared in this scope?? In every class it was already automatically set like
#ifndef _TREEITEM_H
#define _TREEITEM_H
#endif
Since TreePair is nested inside TreeItem, it needs to be
QVector<TreeItem::TreePair> rootData;
Can't get a property of a C++ object inside a QML code.
Object is passed as a parameter to the signal.
Expected that in QML, the property text of the Record object can be extracted. And the value should be abc. QML sees the object as QVariant(Record), and its property text as undefined.
Record is a value-type like QPoint, so it uses Q_GADGET declaration.
hpp:
#ifndef LISTENP_HPP_
#define LISTENP_HPP_
#include <QObject>
#include "Record.hpp"
class ListenP: public QObject
{
Q_OBJECT
public:
ListenP();
virtual ~ListenP();
void emitGotRecord();
signals:
void gotRecord(Record r);
};
#endif /* LISTENP_HPP_ */
cpp:
#include "ListenP.hpp"
ListenP::ListenP() :
QObject()
{
}
ListenP::~ListenP()
{
}
void ListenP::emitGotRecord()
{
emit gotRecord(Record("abc"));
}
hpp for Record:
#ifndef RECORD_HPP_
#define RECORD_HPP_
#include <QObject>
#include <QMetaType>
class Record
{
Q_GADGET
Q_PROPERTY(QString text READ text WRITE setText)
public:
Record(const QString& text = "");
~Record();
QString text() const
{
return m_text;
}
void setText(const QString& text)
{
m_text = text;
}
private:
QString m_text;
};
Q_DECLARE_METATYPE(Record)
#endif /* RECORD_HPP_ */
cpp for Record:
#include "Record.hpp"
Record::Record(const QString& text) :
m_text(text)
{
}
Record::~Record()
{
}
namespace
{
const int RecordMetaTypeId = qMetaTypeId<Record>();
}
QML piece:
Connections {
target: listenPModel
onGotRecord: {
console.log(r)
console.log(r.text)
}
}
main piece:
QGuiApplication app(argc, argv);
auto listenP = std::make_shared<ListenP>();
QQuickView view;
view.rootContext()->setContextProperty("listenPModel", &*listenP);
view.setSource(QStringLiteral("src/qml/main.qml"));
view.show();
QtConcurrent::run([=]
{
QThread::sleep(3);
listenP->emitGotRecord();
});
return app.exec();
Log shows:
qml: QVariant(Record)
qml: undefined
The release notes for Qt 5.5 says for the new features:
Qt Core
You can now have Q_PROPERTY and Q_INVOKABLE within a Q_GADGET, and there is a way to query the QMetaObject of such gadget using the QMetaType system
Indeed, compiling and running your example with Qt 5.4 gives the same result as yours whereas with Qt 5.5 I got Record correctly recognised, i.e. I got as a result:
qml: Record(abc)
qml: abc
Also, as stated in the Q_DECLARE_METATYPE documentation, the type passed to the macro - Record in this case, should provide (1) a public default constructor, (2) a public copy constructor and (3) a public destructor. Since Record is a very simple class, there's no need to provide a copy constructor as the default one is sufficient.