Unable to connect signal to slot in another class - qt

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.

Related

How to use Q_DECLARE_METATYPE on QGraphicsitem derived class?

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);
...
}

Qt Passing signal from Item to a container

I have a QVector of pointers to type X, whose items, i.e. X's own QProcesses. These processes can terminate at arbitrary time. Now, I have constructed signal-slot connection inside class X when a process ends. However, I want to propagate it to the handler class which has a QVector of X* as a member. What is an elegant way for doing this?
You can connect a signal to a signal, hiding the source signal being an implementation detail:
class MyInterface : public QObject {
Q_OBJECT
...
QProcess m_process;
public:
Q_SIGNAL void processEnded();
MyInterface(QObject * parent = 0) : QObject(parent) {
connect(&QProcess, &QProcess::finished, this, &MyInterface::processEnded);
...
}
};
The handler class can listen to these signals and do something with them.
class Handler : public QObject {
Q_OBJECT
QVector<MyInterface*> m_ifaces; // owned by QObject, not by the vector
void addInterface(MyInterface* ifc) {
ifc->setParent(this);
connect(ifc, &MyInterface::processEnded, this, [this, ifc]{
processEnded(ifc);
});
m_ifaces.append(ifc);
}
void processEnded(MyInterface* ifc) {
// handle the ending of a process
...
}
...
};

emitted signal is not caught in derived class

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".

Qt and "No such slot" error

I wrote the class and add a slot:
class graphShow : public QObject {
Q_OBJECT
public:
graphShow(){}
public slots:
void upd(QGraphicsScene &S);
};
Implementation of graphShow::upd is here:
void graphShow::upd(QGraphicsScene &S) {
QGraphicsTextItem* pTextItem = S.addText("Test");
pTextItem->setFlags(QGraphicsItem::ItemIsMovable);
}
Connection:
graphShow gr;
QPushButton* p1 = new QPushButton("Show");
/*...*/
QObject::connect(p1,SIGNAL(clicked()),&gr,SLOT(upd(&scene);));
During compiling I have no errors but when program starts I see this message:
Object::connect: No such slot graphShow::upd(&scene); in main.cpp:93
What am I doing wrong?
You need to set up connection in the following way:
QObject::connect(p1, SIGNAL(clicked()), &gr, SLOT(upd(QGraphicsScene &)));
However this also may not wark, because Qt docs state:
The signature of a signal must match the signature of the receiving
slot. (In fact a slot may have a shorter signature than the signal it
receives because it can ignore extra arguments.)
By the way, you doing it wrong. You could not connect signal without arguments to slot with argument. For your case you should use QSignalMapper.

Creating a dynamic slot in Qt

I am trying to create slots dynamically and connect them. I am able to dynamically create pushButtons and connect them with existing slots. But what if I have a class with some member functions and I want to use these functions as slots.
From a general perspective, I want to create a template for generating slots given a function pointer. This allows us to create slots without changing the existing code and don't have to recompile using MOC.
If this doesn't make sense let me know. Thank you.
-CV
It does make a lot of sense. I assume QSignalMapper is not what you want. If your functions don't have arguments, maybe something like this is enough:
class SlotForwarder : public QObject
{
Q_OBJECT
public:
typedef void (*Function)(); // or whatever. I never get this syntax right...
SlotForwarder(Function function, QObject* parent = 0)
: QObject(parent)
, m_fptr(function)
{}
public slots:
void forward()
{
m_fptr();
}
private:
Function m_fptr;
};
Create one for each function you want to encapsulate and connect to the forward as usual.
Now, if they do have arguments, maybe this Qt Quarterly article might be of assistance.
Dynamic Signals and Slots by Eskil A. Blomfeldt
The technique involves reimplementing the qt_metacall method yourself. The method has this signature:
int QObject::qt_metacall(QMetaObject::Call call, int id, void **arguments)
Call is the kind of metacall: slot, signal, property read or write, etc. Every slot has an id. The parameters are packed (by value or as pointers) inside the arguments array. Reading the code that the moc generates is a good way to understand how it all works.
Data about raw function signatures is available only during compile time, but slots are resolved at runtime. Because of that mismatch, you will need to wrap the functions into a template adapter type that presents a constant interface to your implementation of qt_metacall and converts the arguments array into something the function can understand (cf. Python unpack operator). Boost.Signals does that kind of template hackery.
A continuation of andref's code so as to use any member function as a slot
class SlotForwarder : public QObject
{
Q_OBJECT
public:
typedef void (*Function)();
SlotForwarder(Function function, QObject* parent = 0)
: QObject(parent)
, m_fptr(function)
{}
public slots:
void forward()
{
m_fptr();
}
private:
Function m_fptr;
};
int main(){
QApplication a(argc, argv);
MyClass myClassObject; //contains a function called MemberFunc
//create a slotforwarder object so
SlotForwarder *memberFuncSlot = new SlotForwarder (std::tr1::bind(&MyClass::MemberFunc, &myClassObject));
QObject::connect(ui.button,SIGNAL(clicked()),memberFuncSlot,SLOT(forward());
}

Resources