Q_PROPERTY READ overloaded function - qt

I have my C++/QT code
// .hpp
Q_PROPERTY(int Index READ Index WRITE setIndex NOTIFY IndexChanged)
public:
int Index() const;
int Index(int n) const;
void setIndex(int index):
//.cpp
setContextProperty(QStringLiteral("target"), this)
On the QML side i can access the index using target.Index. What is the syntax for using the taget.Index(int n) for example target.Index(8) gives me errors. Any examples for overloaded read function ?

What you are trying to do is sadly not really possible;
To begin with you'd need to add Q_INVOKABLE to the overloaded method (or make it a slot) in order to make it available to the QML engine:
Q_INVOKABLE int Index(int n) const;
That would mean that target.index is both a function and an int though, and that's of course not possible (isn't in QML/JavaScript and neither in C++). Qt seems to give priority to the property in this case, so you'll still get the "...is not a function" error.
You'll probably have to rename the overloaded function.
Note: The QML engine does handle function overloads (just make sure they are all either slots or marked with Q_INVOKABLE), just not having a function and a property of the same name. So you could have both target.Index() and target.Index(4), but you can't notify of changes that way.

There are two possible approaches:
You should:
Disambiguate the names exposed to QML.
Expose the method not given in Q_PROPERTY as invokable.
E.g.:
class Foo : public QObject {
Q_OBJECT
Q_PROPERTY(int Index READ Index WRITE setIndex NOTIFY IndexChanged)
// QML Interface
Q_INVOKABLE int Index1(int n) const { return Index(n); }
public:
// C++ interface
int Index() const;
int Index(int n) const;
void setIndex(int index);
Q_SIGNAL void IndexChanged();
};
Alternatively, if you're OK with using function interface from JavaScript in place of property interface, you need to take an optional argument via a QVariant. See this question for further details about overloading in QML. E.g.:
class Foo : public QObject {
Q_OBJECT
Q_PROPERTY(int IndexProp READ Index WRITE setIndex NOTIFY IndexChanged)
// QML interface
Q_INVOKABLE int Index(const QVariant & n) const {
if (n.isValid())
return Index(n.toInt());
return Index();
}
public:
// C++ interface
int Index() const;
int Index(int n) const;
void setIndex(int index);
Q_SIGNAL void IndexChanged();
};
The following are all valid then:
target.IndexProp = 5
foo = target.IndexProp
foo = target.Index()
foo = target.Index(2)

Related

No matching constructor for initialization of 'QQmlListProperty<Player>'

new bee here on QT.
I am trying to build an online example that used to work on QT5, but the compilation keeps failing on QT6. I keep getting this error and not sure why.
footballteam.cpp:55:12: No matching constructor for initialization of 'QQmlListProperty<Player>'
qqmllist.h:76:5: candidate constructor not viable:
no known conversion from 'int (*)(QQmlListProperty<Player> *)'
to 'QQmlListProperty<Player>::CountFunction'
(aka 'long long (*)(QQmlListProperty<Player> *)') for 4th argument
Code:
QQmlListProperty<Player> FootBallTeam::players()
{
return QQmlListProperty<Player>(this,this,&FootBallTeam::appendPlayer,
&FootBallTeam::playerCount,
&FootBallTeam::player,
&FootBallTeam::clearPlayers);
}
Classes:
class FootBallTeam : public QObject
{
Q_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(QString coatch READ coatch WRITE setCoatch NOTIFY coatchChanged)
Q_PROPERTY(Player * captain READ captain WRITE setCaptain NOTIFY captainChanged)
Q_PROPERTY(QQmlListProperty<Player> players READ players NOTIFY playersChanged)
... bunch of stuff
private:
//Callback Methods
static void appendPlayer(QQmlListProperty<Player>*, Player*);
static int playerCount(QQmlListProperty<Player>*);
static Player* player(QQmlListProperty<Player>*, int);
static void clearPlayers(QQmlListProperty<Player>*);
....
class Player : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(bool playing READ playing WRITE setPlaying NOTIFY playingChanged)
Q_PROPERTY(QString position READ position WRITE setPosition NOTIFY positionChanged)
public:
explicit Player(QObject *parent = nullptr);
QString name() const;
bool playing() const;
QString position() const;
void setName(QString name);
void setPlaying(bool playing);
void setPosition(QString position);
signals:
void nameChanged(QString name);
void playingChanged(bool playing);
void positionChanged(QString position);
private :
QString m_name;
bool m_playing;
QString m_position;
};
I looked into this thread, but did not help much.
Pass QQmlListProperty from QML to C++ as parameter
Any ideas why it does not compile on QT6?
thank you.
As pointed out by absolute.madnes, the fix was to change int to qsizetype
qsizetype FootBallTeam::playerCount(QQmlListProperty<Player> * list)
{
return reinterpret_cast<FootBallTeam*>(list->data)->playerCountCustom();
}
Player *FootBallTeam::player(QQmlListProperty<Player> * list, qsizetype index)
{
return reinterpret_cast<FootBallTeam*>(list->data)->playerCustom(index);
}

using QList<T> in a connect( ) call

I am writing my first application in Qt4, basically using the books of Blanchette/Summerfield andSams 24 hours, and a lot of Qt search on internet.
my actual call is:
connect( thumbNailView,
SIGNAL(leftClicked(QListWidgetItem *)),
leftKeypointList,
SLOT(openItem(QListWidgetItem *)));
which gives the following error:
"no matching function for call to DAPPMainWindowWidget::connect(DAPPListWidget*&, const char [32], DAPPKeypointList*&, const char [29])"
I also connected this signal to another object which works flawless:
connect( thumbNailView,
SIGNAL(leftClicked(QListWidgetItem *)),
leftImage,
SLOT(openItem(QListWidgetItem *)));
Both leftImage and leftKeypointList are pointers to objects to a standard QWidget and and a custom object DAPPKeypointList : public QList with DAPPKeypoint holding index and position
of the keypoint.
My idea is that I cannot simply pass a pointer to QList sort of object the same way as I do a pointer to a standard Qwidget.
below follow:
in my DAPP.h
private:
DAPPKeypointList * leftKeypointList;
DAPPKeypointList * rightKeypointList;
and classes:
class DAPPKeypoint {
public:
DAPPKeypoint();
~DAPPKeypoint();
QPoint getKeypointPos();
void setKeypointPos(QPoint);
int getKeypointIndex();
void setKeypointIndex(int);
private:
QPoint keypointPos;
int keypointIndex;
};
class DAPPKeypointList : public QList<DAPPKeypoint> {
Q_OBJECT
public: DAPPKeypointList();
~DAPPKeypointList();
private slots:
void openItem(QListWidgetItem *);
};
in my cpp files:
DAPPKeypoint.cpp
#include "DAPP.h"
DAPPKeypoint::DAPPKeypoint(){}
DAPPKeypoint::~DAPPKeypoint(){}
QPoint DAPPKeypoint::getKeypointPos(){ return keypointPos; }
void DAPPKeypoint::setKeypointPos(QPoint kpPos){ keypointPos = kpPos; }
int DAPPKeypoint::getKeypointIndex(){ return keypointIndex; }
void DAPPKeypoint::setKeypointIndex(int kpIndex){ keypointIndex = kpIndex; }
DAPPKeypointList.cpp: (for the moment just a template ...)
#include "DAPP.h"
DAPPKeypointList::DAPPKeypointList(){}
DAPPKeypointList::~DAPPKeypointList(){}
void DAPPKeypointList:: openItem(QListWidgetItem *) {}
And DAPPMainWindowWidget.cpp :
Parts that are relevant (if you need more, let me know, but I think this is sufficient to have an idea of the problem):
leftKeypointList = new DAPPKeypointList;
rightKeypointList = new DAPPKeypointList;
leftImage = new DAPPImageWidget(leftImageLabel);
connect(thumbNailView,SIGNAL(leftClicked(QListWidgetItem *)) ,leftKeypointList ,SLOT(openItem(QListWidgetItem *)));
connect(thumbNailView,SIGNAL(leftClicked(QListWidgetItem *)) ,leftImage ,SLOT(openItem(QListWidgetItem *)));

QVariant call a function of a stored object, defined in the main part of a project

The common part (crating a lib) of my project currently holds a interface Class of the type:
class CanBeAddedToGroup{
public:
void addToGroup(Group& )=0;
}
Now i also wantred to use the programm on a Class containing data in a QVariant, so i started it off simple:
class DataContainingClass: public CanBeAddedToGroup{
QMap<QString,QVarient> data;
public:
void addToGroup(Group& ){
QMap<QString,QVarient>::itterator itter = data.begin();
QMap<QString,QVarient>::itterator end= data.end();
for(;itter !=end;itter ++){
<Handle Data>
}
}
};
}
Now one of the datatypes addedt to the list (outside the lib) is of the type:
class DataClass: public QObject, public CanBeAddedToGroup{
void addToGroup(Group& );
}
Q_DECLARE_METATYPE(DataClass)
And it is added to the map using "QVariant::fromValue(", now i need a way in the "DataContainingClass" to check if the Data is derived from a QObject, so i know static_cast(variant.data()) is valid.
Then i could try to dynamic_cast the Object pointer to CanBeAddedToGroup, and call it.
--- EDIT ---:
The Problem IS NOT: Having a QObject and check if it inherits another QObject, it is not even checking if a Class inherits from another one, it is to know if the data i have actually IS a QObject.
Minimal Example:
Header File:
#include <QObject>
#include <QDebug>
class DmbClass: public QObject{
Q_OBJECT
public:
DmbClass(){TST="RealOne";}
DmbClass(const DmbClass&d){TST="Clone";}
QString TST;
};
Q_DECLARE_METATYPE(DmbClass)
class Tst{
public:
virtual void tstFunct()=0;
};
class CanClass: public QObject, public Tst{
Q_OBJECT
public:
CanClass(){TST="RealOne";}
CanClass(const CanClass&d){TST="Clone";}
QString TST;
virtual void tstFunct() override{
qDebug()<<"tst";
}
};
Q_DECLARE_METATYPE(CanClass)
class DmbGadget{
Q_GADGET
public:
DmbGadget(){TST="RealOne";}
DmbGadget(const DmbGadget&d){TST="Clone";}
QString TST;
};
Q_DECLARE_METATYPE(DmbGadget)
C File:
// QObject in QVariant
DmbClass dC;
QVariant varC=QVariant::fromValue(dC);
const void* vPC = varC.data();
DmbClass dCc = varC.value<DmbClass>();
QObject* objC = (QObject*)varC.data();
QObject* schouldWork = objC->parent();
Tst* schouldBeNull = dynamic_cast<Tst*>(objC);
// Object using correct base class in QVariant
CanClass dT;
QVariant varT=QVariant::fromValue(dT);
const void* vPT = varT.data();
CanClass dTc = varC.value<CanClass>();
QObject* objT = (QObject*)varT.data();
QObject* schouldWork2 = objT->parent();
Tst* schouldNotNull = dynamic_cast<Tst*>(objT);
schouldNotNull->tstFunct();
// Q_Gadget in QVariant
DmbGadget dG;
QVariant varG=QVariant::fromValue(dG);
const void* vPG = varG.data();
DmbGadget dGg = varG.value<DmbGadget>();
QObject* objD = (QObject*)varG.data();
//QObject* schouldSegFault = objD->parent();
// base value in QVariant
QVariant var4=4;
const void* vP4 = var4.data();
QObject* obj4 = (QObject*)var4.data();
//QObject* schouldSegFault2 = obj4 ->parent();
I need a way to distinguisch cases 1&2 from 3&4 ("schouldSegFault"), without using something only defined outside of the lib.
I Already Tryed:
int tst4 = qRegisterMetaType<CanClass>("CanClass");
QMetaType help2(tst4);
But help2 has a MetaObject of 0, so i cant check for the inheriance from QObject.
Edit/for who added "Proper way to check QObject derived class type in Qt" ther was te issue in my programm that the class inherits from another QObjectclass so i cant chack for inheriance of my interface (even when defined as Q_Gadget) using inherits, since it would only be true for the first element.
PS: For everyone trying to call functions on a QVariant containing a Object rather than a pointer might be interested in this approach:
How to support comparisons for QVariant objects containing a custom type? / https://pastebin.com/tNLa0jSa
While having a global registry for types is what i wished i could avoid for the case.
Just try to use QVariant::value and see if the value in a QVariant can be converted to your target class. Here's a minimal example:
#include <QObject>
#include <QVariant>
#include <QVariantMap>
#include <QDebug>
class MyQObjectClass : public QObject {
Q_OBJECT
public:
explicit MyQObjectClass(QObject *parent = nullptr) : QObject(parent) {}
void greet() { qDebug() << "I am a MyQObjectClass!"; }
};
Q_DECLARE_METATYPE(MyQObjectClass*)
int main(int, char *[])
{
MyQObjectClass obj;
QVariantMap map;
map.insert("foo", QString("Hello World"));
map.insert("bar", QVariant::fromValue(&obj));
QVariantMap::iterator iter = map.begin();
QVariantMap::iterator end= map.end();
for(;iter !=end;iter ++) {
auto value = iter.value();
// Try to convert to MyQObjectClass*
auto obj = value.value<MyQObjectClass*>();
if (obj != nullptr) {
qDebug() << iter.key() << "is an instance of MyQObjectClass";
obj->greet();
continue;
}
qDebug() << iter.key() << "is not an instance of MyQObjectClass";
}
}
#include "main.moc"
Running it should yield the following output on the console:
"bar" is an instance of MyQObjectClass
I am a MyQObjectClass!
"foo" is not an instance of MyQObjectClass
The important parts:
Make sure the class you want to store in a QVariant derives from QObject and has the Q_OBJECT macro.
When iterating over the map, use QVariant::value() and try to convert the contained value to your target class. In the example, I use QVariant::value<MyQObjectClass*>() - according to the documentation, this either returns the contained instance of MyQObjectClass* if the value can be converted to it or - which is the case if the QVariant contains either basic values or gadgets - a default constructed value. In the case of a pointer this would be a null pointer, so just check if the value returned is null. That's it.
Never work on Qvariant::data() directly.
Update
Just as a remark: The Qobject class declared the copy constructor and assignment operators as private:
From the official documentation:
QObject has neither a copy constructor nor an assignment operator. This is by design. Actually, they are declared, but in a private section with the macro Q_DISABLE_COPY(). In fact, all Qt classes derived from QObject (direct or indirect) use this macro to declare their copy constructor and assignment operator to be private. The reasoning is found in the discussion on Identity vs Value on the Qt Object Model page.
Hence, you cannot copy around instances of QObject (and consequentially you cannot store them in QVariant). Instead, you pass around pointers to QObject instances.
Update #2
If your interface class cannot derive directly from QObject, you might consider using Qt's plugin mechanism instead. Here's the above example slightly edited to fit this approach:
#include <QObject>
#include <QVariant>
#include <QVariantMap>
#include <QDebug>
class MyInterfaceClass {
public:
MyInterfaceClass() {}
virtual ~MyInterfaceClass() {}
virtual void greet() = 0;
};
#define MyInterfaceClass_IID "org.example.MyInterfaceClass"
Q_DECLARE_INTERFACE(MyInterfaceClass, MyInterfaceClass_IID)
class MyConcreteClass : public QObject, public MyInterfaceClass {
Q_OBJECT
Q_INTERFACES(MyInterfaceClass)
public:
MyConcreteClass(QObject *parent = nullptr) : QObject(parent) {}
void greet() override { qDebug() << "I am a MyInterfaceClass!"; }
};
int main(int, char *[])
{
MyConcreteClass obj;
QVariantMap map;
map.insert("foo", QString("Hello World"));
map.insert("bar", QVariant::fromValue(&obj));
QVariantMap::iterator iter = map.begin();
QVariantMap::iterator end= map.end();
for(;iter !=end;iter ++) {
auto value = iter.value();
// Try to convert to QObject*:
auto obj = value.value<QObject*>();
if (obj != nullptr) {
// Try if we can cast to our interface class:
auto ifc = qobject_cast<MyInterfaceClass*>(obj);
if (ifc != nullptr) {
qDebug() << iter.key() << "is an instance of MyInterfaceClass";
ifc->greet();
}
continue;
}
qDebug() << iter.key() << "is not an instance of MyInterfaceClass";
}
}
#include "main.moc"
You need to:
Define your interface class and register it with Qt using the Q_DECLARE_INTERFACE macro.
Declare your concrete classes, deriving from QObject and your interface class. In addition, you need to tell Qt about the interface part using the Q_INTERFACES macro.
When checking the values in your map, first try to convert to a QObject* via QVariant::value(). If this succeeds, you can try to qobject_cast to your interface class.
Your design is completely broken: QObjects cannot be used as unrestricted values. They cannot be copied nor moved, and your implementations of copy constructors are hiding this fundamental fact.

QObject retunrs with exception even after the copy constructor being declared

I am trying to write a sample code for qt script. I thought I am doing the right thing when I declare the QObjecy with the copy construtor and I also took the liberty to declare the = operator. But this code keeps giving me the
'QObject::QObject' : cannot access private member declared in class 'QObject'
Error.
I am declaring a MyClass which is a QObject as follows. I am aware of the fact that this can some one see what I am doing a wroing here.
The header:
#ifndef SCRIPT_CLASSES_H
#define SCRIPT_CLASSES_H
#include "QObject"
#include "QtScript/QScriptValue"
#include "QtScript/QScriptable"
#include "QtScript/QScriptClass"
class MyClass : public QObject
{
Q_OBJECT
// Q_PROPERTY( int _id WRITE setId READ id )
public :
MyClass(QObject *aparent =0) ;
~MyClass();
// bool operator =(MyClass obj);
public slots:
void setId(int d);
int id() const ;
// bool MyClass::equals(const MyClass &other);
private :
int _id;
};
class QScriptEngine;
class Script_Classes : public QObject, public QScriptClass
{
public:
Script_Classes(QScriptEngine *engine);
~Script_Classes();
private :
static QScriptValue myClassToScript(QScriptEngine *engine,const MyClass &in);
static void myClassFromScript(const QScriptValue &object, MyClass &out);
};
#endif // SCRIPT_CLASSES_H
And my source class is as follows:
#include "script_classes.h"
#include "QMetaType"
#include "QtScript/QScriptEngine"
#include "QtScript/QScriptValue"
Q_DECLARE_METATYPE(MyClass)
Q_DECLARE_METATYPE(MyClass*)
MyClass::MyClass(QObject *aparent) : QObject (aparent){}
MyClass::~MyClass(){}
void MyClass::setId(int d){
_id = d;
}
int MyClass::id() const{
return _id;
}
bool MyClass::equals(const MyClass &other)
{
return id() == other.id();
}
bool MyClass::operator =(MyClass obj){
return id()==obj.id();
}
Script_Classes::Script_Classes(QScriptEngine *engine):QObject(engine),QScriptClass(engine)
{
qScriptRegisterMetaType<MyClass>(engine, myClassToScript, myClassFromScript);
MyClass testClass(this);
}
void Script_Classes::myClassFromScript(const QScriptValue &object, MyClass &out){
out.setId(object.property("id").toInt32());
}
QScriptValue Script_Classes::myClassToScript(QScriptEngine *engine, const MyClass &in)
{
QScriptValue value = engine->newObject();
value.setProperty("id", in.id());
return value;
}
The problem is that you cannot copy a QObject. From the QObject documentation:
QObject has neither a copy constructor nor an assignment operator.
This is by design. Actually, they are declared, but in a private
section with the macro Q_DISABLE_COPY(). In fact, all Qt classes
derived from QObject (direct or indirect) use this macro to declare
their copy constructor and assignment operator to be private. The
reasoning is found in the discussion on Identity vs Value on the Qt
Object Model page.
The main consequence is that you should use pointers to QObject (or to
your QObject subclass) where you might otherwise be tempted to use
your QObject subclass as a value. For example, without a copy
constructor, you can't use a subclass of QObject as the value to be
stored in one of the container classes. You must store pointers.
Also QObject has not the == implemented so you cannot compare two instance of your class.
PS What is the point of overloading the = operator and making it operate like the == one? This makes your code obfuscated and debugging much more complex.
EDIT
Assume you have the following simple class inheriting from QObject
class A : public QObject
{
Q_OBJECT
public:
int anInt;
double aDouble;
}
Assume now that you want to create two inctances of A somewhere in your code.
A a1;
A a2;
It is illegal to call a1=a2 since QObject's = operator is not public. What you need to do in order to achieve the copying of the data is to do it manually :
a2.anInt = a1.anInt
a2.aDouble = a1.aDouble
On the other hand if you used pointers it is totally legal to point at the same object
A* a1 = new A;
A* a2 = new A;
a1 = a2;
Now both a1 and a2 point at the same memory location and have the same data. If you want to have two different objects you could create a constructor with argument a pointer to the object. For our simple class you could have:
A::A(A* a)
{
anInt = a->anInt;
aDouble = a->aDouble;
}
and now it is legal do:
A a1;
A a2(&a1);
If you wonder why QObject does not allow assignment read the Identity vs Value part of the Object Model documentation.

Is it possible to emit a Qt signal from a const method?

In particular, I am implementing a QWizardPage ("MyWizardPage") for a QWizard, and I want to emit a signal ("sigLog") from my override of the QWizardPage::nextId virtual method.
Like so:
class MyWizardPage
: public QWizardPage
{
Q_OBJECT
public:
MyWizardPage();
virtual int nextId() const;
Q_SIGNALS:
void sigLog(QString text);
};
int MyWizardPage::nextId() const
{
Q_EMIT sigLog("Something interesting happened");
}
But when I try this, I get the following compile error on the Q_EMIT line:
Error 1 error C2662: 'MyWizardPage::sigLog' : cannot convert 'this' pointer from 'const MyWizardPage' to 'MyWizardPage &'
It is possible to emit a signal from a const method by adding "const" to the signal declaration, like so:
void sigLog(QString text) const;
I tested this and it does compile and run, even though you don't actually implement the signal as a normal method yourself (i.e. Qt is okay with it).
You may try to create another class , declare it as friend for your wizard page and add to wizard as a mutable member. after that you may emit it's signal instead of wizard's.
class ConstEmitter: public QObject
{
Q_OBJECT
...
friend class MyWizardPage;
Q_SIGNALS:
void sigLog(QString text);
};
class MyWizardPage
: public QWizardPage
{
Q_OBJECT
public:
MyWizardPage();
protected:
mutable CostEmitter m_emitter;
Q_SIGNALS:
void sigLog(QString text);
};
int MyWizardPage::nextId() const
{
Q_EMIT m_emitter.sigLog("Something interesting happened");
}
MyWizardPage::MyWizardPage()
{
connect(&m_emitter,SIGNAL(sigLog(QString)),this,SIGNAL(sigLog(QString)));
}
or you may just use
int MyWizardPage::nextId() const
{
Q_EMIT const_cast<MyWizardPage*>(this)->sigLog("Something interesting happened");
}
that is not recommended way, because const_cast is a hack, but it's much shorter :)

Resources