class Settings : public QObject
{
Q_OBJECT
public:
Settings();
~Settings();
void setValue(QString key, QVariant value);
// [...]
signals:
void settingsChanged();
// [...]
class ApplicationSettings : public Settings
{
public:
explicit ApplicationSettings();
~ApplicationSettings();
public slots:
void save();
// [...]
Every time I change a value via setvalue(...)in the base class,
I do emit settingsChanged().
In the constructor of ApplicationSettings I say:
connect(this, SIGNAL(settingsChanged()), this, SLOT(save()));
But save() is never called.
As I've been writing this question I noticed that I did not include Q_OBJECT in my derived class. Adding this, the signal was connected correctly. I think this question may still be useful for others, because it was also new for me that the Q_OBJECT-macro of the base class is not "inherited".
Related
I want to use my objects as QVariants and for queued connections. Therefore I want to use Q_DECLARE_METATYPE(My_Item) and from the documentation I learned that I need a public copy constructor. I tried to write one, but I failed. Than I did read this copy constructor of derived QT class and the answer by BЈовић. From there I understand that what I intended to do is not going to work. What do I have to do make my objects useable for the Metatypesystem?
My_Item is based on My_Super_Item, which look like this:
class My_Item: public My_Super_Item {
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
explicit My_Item(Application *a, QString astring);
...
}
and
class My_Super_Item : public QObject, public virtual QGraphicsItem {
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
My_Super_Item(My_Application *a, QString astring);
...
}
I have the following class, set in a ContextProperty at the start of the application:
class MyClass : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE MyClassModel getModel() const { return m_myClassModel; }
private:
MyClassModel m_myClassModel;
}
In one of its methods, MyClass fills m_myClassModel with data (coming from a server).
MyClassModel also inherits QObject (because of Q_PROPERTY macros):
class MyClassModel : public QObject
{
Q_OBJECT
// Lots of Q_PROPERTY macros
Q_PROPERTY(int stuff READ stuff WRITE setStuff NOTIFY stuffChanged)
public:
...
signals:
void stuffChanged();
...
}
Then, in a QML file, MyClassModel is used to trigger signals and update graphical elements:
Item
{
anchors.fill: parent
CustomLabel
{
Connections
{
target: myClass.myClassModel()
onStuffChanged: { console.log("signal triggered!") }
}
}
}
Because of Q_INVOKABLE MyClassModel getModel() const { return m_myClassModel; }, I'm getting this error:
error: C2248: 'QObject::QObject' : cannot access private member declared in class 'QObject'
I think I understand the cause of this error, but I am not sure about what I should do to prevent it. I need to have access to MyClassModel from MyClass in order to fill it with data, yet I cannot return it into my QML file.
You are returning MyClassModel from getModel. This means copying the object. Copying MyClassModel involves a call to the implicitly generated copy constructor, which in turn calls copy constructor of base class (QObject). But copy constructor of QObject is private, this is why you get an error. Designers of Qt have decided long time ago that QObject should be non-copyable.
Solution is to return a pointer:
Q_INVOKABLE MyClassModel* getModel() const { return &m_myClassModel; }
My model is in C++ and front end is QML. The model consist of an interface class which contain other components. In simplied form (proof of concept stage) This interface class is pure virtual class called Base which is derived from QObject. I have a Derived class derived from Base
I am emitting signal in the derived class when data changes. My problem is how to catch this signal and process in QML?
derived.obj:-1: error: LNK2019: unresolved external symbol "public: void __thiscall Derived::somethingChanged(void)" (?somethingChanged#Derived##QAEXXZ) referenced in function "public: virtual void __thiscall Derived::doSomething(void)" (?doSomething#Derived##UAEXXZ)
My Base.h class is:
#include <QObject>
class Base : public QObject
{
Q_OBJECT
public:
explicit Base(QObject *parent = 0);
~Base();
virtual void doSomething() = 0;
signals:
public slots:
};
Derived.h is
#include "base.h"
class Derived : public Base
{
Q_OBJECT
public:
Derived();
~Derived();
virtual void doSomething();
signals:
void somethingChanged();
};
Derived.cpp is
#include "derived.h"
#include <QDebug>
Derived::Derived()
{
}
Derived::~Derived()
{
}
void Derived::doSomething()
{
qDebug() << "doSomething() called in Derived";
emit somethingChanged(); // this doesn't compile!
}
Connections {
target: What? // what should I put here,
onSomethingChanged: console.log("The application data changed!")
}
Again the problem is what do I put for target property? The model will only expose the interface class to qml which is the Base class but the signal is actually emitted in derived class. Should the signal be also virtual by any chance? How should I receive this signal in QML?
The MOC is the one who implements the function (your signal) void somethingChanged();.
An example could look like this in the moc_XYZ.cpp file.
// SIGNAL 13
void Derived::doSomething()
{
QMetaObject::activate(this, &staticMetaObject, 13, Q_NULLPTR);
}
So how do you make the MOC happy?
Add Q_OBJECT in your derived.h
In order to create interfaces to be used in Qt I have found two cases:
Based on QObject
This is the most easy form, and you are in the right way. Just create a class based on QObject with abstract methods and declare signals. Derived classes must not declare the signals again, just emit them when needed.
This is your case. MOC generator need to know that Base interface has an signal and it can be emitted. Just declare signals in Base instead derived classes.
Pure virtual class (extra info)
Sometimes you need to derive from any QObject-based class (e.g. QAbstractListModel) but it need to implement some interfaces too. C++ allows multiple inheritance, but Qt doesn't like classes that derive from two or more QObject-based classes.
So you should create a plain pure virtual class, and declare signals as any other unimplemented method.
// Base
class Base
{
public:
Base();
virtual ~Base();
virtual void doSomething() = 0;
signals:
virtual void somethingChanged() = 0;
};
Now, derive from Base and declare the signal again:
// Derived
class Derived : public QObject, public Base
{
Q_OBJECT
public:
explicit Derived(QObject *parent = 0);
~Derived();
//Implmetations of Base methods
public:
void doSomething();
//Declaration of Base signals
signals:
void somethingChanged();
}
I have 2 classes. Class A and Class B. I am emitting a signal from class A which I want the B to recieve.
I am doing it following way
In Listener File
Header File:
Class Listener:public DDSDataReaderListener
{
//Some code
public:
A m_objectSendData;
}
Implementation File:
void Listener::ondataavailable(DDSDataReader *reader)
{
m_objSendData.GetDDSData();
}
In Class A
Header File:
Class A:public QObject
{
Q_OBJECT
public:
void GetDDSData();
signals:
void Signal_Data();
}
.cpp File
A::A(QWidget *parent):QObject(parent)
{
}
void A::GetDDSData()
{
emit Signal_Data();
}
In Class B
Header File:
Class B:public QObject
{
Q_Object
public:
A objGetData;
public slots:
void getData();
}
Implementation File:
B::B(QWidget *parent):QObject(parent)
{
//Some part of code
connect(&objGetData,SIGNAL(Signal_Data()),this,SLOT(getData());
}
void B::getData()
{
//Watever is to be updated
}
I tried debugging. It is going till emit part correctly. However it is not reaching the slot.
Can someone please help me with this.
Thank You.
Without full code, it's quite difficult to identify the exact issue of the problem, so I'll outline a few important points to check.
To ensure you can use the signal and slots mechanism, you should ensure that your class is derived, from QObject or a class already derived from QObject in its hierarchy and your class must contain the Q_OBJECT macro, for example: -
class A : public QObject // derived from QObject
{
Q_OBJECT // your class must have this macro for signals and slots
public:
A();
};
Omitting the macro is probably the most common of mistakes.
To specify a slot, you add it to either the public or private slot section of your class: -
class B : public QObject // derived from QObject
{
Q_OBJECT // your class must have this macro for signals and slots
public:
B();
public slots:
void SlotB(); // slot declared public
private slots:
void SlotBPrivate(); // slot declared private.
};
Once a signal is declared in a class, a slot to receive the signal should match the arguments passed in and when you connect a signal to a slot, you must not add the function argument names.
Therefore: -
connect(&objectA, SIGNAL(SignalA(int in), this, SIGNAL(SlotA(int param)); //will fail due to the argument names
It should be: -
connect(&objectA, SIGNAL(SignalA(int), this, SIGNAL(SlotA(int));
Finally, if you're using Qt 5, you can use the new connection call, which doesn't require you to specify any argument, but instead takes the addresses of slot and signal functions.
connect(&objectA, &A::SignalA, this, &B::SlotA));
Since it references the address of a function, in actuality, the functions don't need to be classed as a slot and will still be called.
Hope that helps.
Actually I believe an answer is given in one of the comments.
One more thing, you didn't show enough code but I suspecting that you program leaves scope of objectA variable and your emitting object is just destroyed before it can emit any signal (objectA is local variable created on stack not on heap). – Marek R 1 hour ago
you allocate your Object on stack, so it gets destroyed as soon as it gets out of scope, together with destroy it gets disconnected from all signals/slots it has connections to.
So that's why you don't see any errors/warning messages because code itself is completely legit. You should new() your object to get it allocated in heap.
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 :)