Connect all of an objects signals to a single slot - c++

Been looking around a bit and people seem to have a similar issue but with multiple signals from different sources etc. My situation is that I have a object that signals if it succeded, failed or got canceled. These signals are passed along to another class and are'nt connected to a slot, just a signal. Now I would like to fix so that no matter what signal the object sends (failed, succeded, canceled) a slot will be called that will delete the object. In short, I want a way of connecting every signal of an object to a slot.
Want to do something like this:
connect(myObject, allSignals, this, handleObjectDone());
void handleObjectDone() {
myObject->deleteLater();
}
Is there any way of doing this? Or should I just pass two signals everytime it does something, for example emit readyToBeDeleted() and emit succeded()?
Thanks!

Setting aside any qualms about whether connecting all the signals in one object to a single slot in another object is actually a wise thing to do, below is a function that does that, along with a unit test to verify that it works.
If you watch stdout while you run this, you will see it print out all the connections it is making. When it runs, clicking on the QLineEdit will cause the QLineEdit to emit a signal, which will (of course) cause the QApplication::quit() slot to be called, so the application will exit.
#include <stdio.h>
#include <QApplication>
#include <QLineEdit>
#include <QMetaMethod>
#include <QMetaObject>
void ConnectAllSignalsToSlot(QObject * sourceObject, QObject * targetObject, const char * slotName)
{
const QMetaObject * mo = sourceObject->metaObject();
if (mo)
{
int numMethods = mo->methodCount();
int firstMethod = mo->methodOffset(); // set to 0 instead if you want to connect signals from superclasses too
for (int i=firstMethod; i<numMethods; i++)
{
QMetaMethod mm = mo->method(i);
if (mm.methodType() == QMetaMethod::Signal)
{
QString signalString = QString("2") + mm.signature();
printf("Connecting up signal [%s] on object %p to slot [%s] on object %p\n", signalString.toUtf8().constData(), sourceObject, slotName, targetObject); // just so we can see what it's doing
QObject::connect(sourceObject, signalString.toUtf8().constData(), targetObject, slotName);
}
}
}
else printf("Error, sourceObject has no QMetaObject????\n");
}
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
QWidget * testSource = new QLineEdit;
testSource->show();
ConnectAllSignalsToSlot(testSource, &app, SLOT(quit()));
return app.exec();
}

You can connect any number of signals to any number of slots (as well as other signals). It makes perfect sense to connect the signals to two slots for this purpose. The slots are called in the order they are connected. Emitting two signals consecutively is perfectly reasonable as well. Of course readyToBeDeleted() should be emitted after succeeded() so that the object isn't deleted before emitting its result signal.
Unless I'm misunderstanding you, it's that simple.

Related

timer couldn't work with wiringPiISR (QtQuick application)

I have created a class Capteur_Input and one of the options in the constructor creates an interrupt using wiringPiISR
wiringPiISR(m_pin, INT_EDGE_RISING, isrInput);
my class also has an attribute m_impulsion and I am incrementing this value each time that an interruption happens.
this what my interrupt handler looks like
void Capteur_Input::isrCallback()
{
if(m_pin== Pin_vitesse)
{
increment_impulsion();
emit digital_inputChanged(m_impulsion);
}
else
emit digital_inputChanged(m_value);
}
in my main.cpp I created an instance of this class
static void isrInput_vitesse();
static Capteur_Input vitesse(Pin_vitesse,PUD_OFF,INT_EDGE_RISING,isrInput_vitesse);
static void isrInput_vitesse()
{
vitesse.isrCallback();
}
every thing is working fine, the qml and C++ part.
and now I want to calculate the number of impulse detected per second. but I couldn't do it.
my class Capteur_Input also has a timer, I configured it in the constructor
m_timer =new QTimer (this);
m_timer->setTimerType(Qt::PreciseTimer);
connect (m_timer,SIGNAL(timeout()),this,SLOT(onTimeout()));
m_timer->start(500);
and I tried to test in the SLOT onTimeout() someting but this qDebug()<<"VITESSEEEEEEEE"<<m_pin <<readPin()<<vitesse; never shows up. I don't know why maybe because wiringPiISR is a thread and has a higher priority than the timer?
can someone explain to me please, how to make a timer that calculates the exact time and make the interrupt work in the same time?
the timer is working for the other instances of this class that are just inputs no interruptions
void Capteur_Input::onTimeout()
{
qDebug()<<"time is up"<<m_pin;
if(m_pin== Pin_vitesse)
{
qDebug()<<"m_pin== Pin_vitesse";
int vitesse;
vitesse= int (calcul_vitesse/4*2.166);//*0.001/3600;
qDebug()<<"VITESSEEEEEEEE"<<m_pin <<readPin()<<vitesse;
emit vitesse_Changed(vitesse);
qDebug()<<"VITESSEEEEEEEE"<<m_pin <<readPin()<<vitesse;
}
else{
emit digital_inputChanged(readPin());
qDebug()<<"signal DIGITAL emitted m_pin"<<m_pin <<"value"<<readPin();
}
}
actually the slot onTimeout is working for these 2 instances
#define Pin_vitesse 3
#define PinFrein 0
#define PinClignotnat_G 2
Capteur_Input frein(PinFrein,PUD_UP,NO_INTERRUPT);
Capteur_Input clignotant_G(PinClignotnat_G,PUD_DOWN,NO_INTERRUPT);
and is not working for this one which is an interrupt static Capteur_Input vitesse(Pin_vitesse,PUD_OFF,INT_EDGE_RISING,isrInput_vitesse);
and this what I got as an output
time is up 0
signal DIGITAL emitted 0 1
time is up 2
signal DIGITAL emitted 2 0
time is up 0
signal DIGITAL emitted 0 1
the timer is working for the other instances and it is not working for the one that is an interrupt
Static QObject instance is not supported in Qt, as stated below (QObject reentrancy section ):
In general, creating QObjects before the QApplication is not supported
and can lead to weird crashes on exit, depending on the platform. This
means static instances of QObject are also not supported. A properly
structured single or multi-threaded application should make the
QApplication be the first created, and last destroyed QObject.
If you need a callback when isr interrupt comes up, a static pointer should work:
static void isrInput_vitesse();
static Capteur_Input *vitesse = nullptr;
static void isrInput_vitesse()
{
if(!vitesse) //not initialized yet
return;
QMetaObject::invokeMethod( vitesse, "isrCallback", Qt::QueuedConnection ); //or blockingQueue if you need to handle it directly in Qt way.
}
The vitesse pointer should be initialized in main() after the initialization of QApplication instance.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//..... your main application body
vitesse = new Capteur_Input(Pin_vitesse,PUD_OFF,INT_EDGE_RISING,isrInput_vitesse);
//...
}
Your timeout signal might be interfered or delayed.
You may try to specify a Qt::Connectiontype to force Qt to treat your timeout signal as soon as it is emitted.
QObject::connect(m_timer, &QTimer::timeout, this, &Capteur_Input::onTimeOut, Qt::DirectConnection);
This will deliver the timeout signal to the ontimeOut slot as soon as it is emitted.

Find the sender of the `destroyed (QObject*)` signal

I am currently wondering how to reasonably use the QObject::destroyed(QObject*) signal.
An observation
I noticed that QWidget-derived objects are treated slightly different. Consider the following small self-contained and compiling example:
/* sscce.pro:
QT += core gui widgets
CONFIG += c++11
TARGET = sscce
TEMPLATE = app
SOURCES += main.cpp
*/
#include <QApplication>
#include <QPushButton>
#include <QTimer>
#include <QtDebug>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::destroyed,
[=](QObject *o) { qDebug() << o; });
delete button;
QTimer *timer = new QTimer;
QObject::connect(timer, &QTimer::destroyed,
[=](QObject *o) { qDebug() << o; });
delete timer;
return app.exec();
}
This is its output:
QWidget(0x1e9e1e0)
QObject(0x1e5c530)
So presumably, the signal is emitted from QObject's d-tor, so only the QObject base remains when the slot is called for the QTimer. However, QWidget's d-tor seems to intercept as it still identifies itself as a QWidget from the slot.
And the problem
Let's assume we have a timer pool that organizes a couple of timers in a QList<QTimer *>:
struct Pool {
QTimer *getTimer() {
return timers.at(/* some clever logic here */);
}
QList<QTimer *> timers;
};
Now an incautious user might delete the timer that was borrowed to him/her. Well, we can react, and simply remove that timer from the list. A slot will do the trick:
Pool::Pool() {
/* for each timer created */
connect(theTimer, SIGNAL(destroyed(QObject*),
this, SLOT(timerDestroyed(QObject*));
}
void Pool::timerDeleted(QObject *object) {
QTimer *theTimer = /* hrm. */
timers.removeOne(theTimer);
}
But what now? Hrm. When the slot is called, the QTimer already is in destruction and partially destroyed - only its QObject base remains. So I objously cannot qobject_cast<QTimer *>(object).
To resolve this issue, I could think of the following tricks:
Store QObjects in the list. Then I'd have to downcast every time I use an item from the list. This could be done using static_cast, though, as I know there will only be QTimers in the list, so no need for dynamic_cast or qobject_cast.
Insteat of removeOne traverse the list using an iterator and then compare each QTimer item directly to the QObject. Then use QList::erase or such.
static_cast or even reinterpret_cast the QObject to a Qtimer nonetheless.
What should I do?
If you're looking for tricks, you could simply use the base QObject objectName and remove the destroyed timer based on that.
It seems clear that your problem is one of object ownership; in particular, how to convey who is responsible for destroying an object. If your Pool object owns the QTimer objects (and thus the user should not delete them), make it clear through the interface, for example returning a QTimer& instead of a QTimer* from your getTimer method. I'm not really well versed in Qt, but if you actually wanted to transmit ownership of the object returned from a method and thus make the user responsible of its deletion, you'd likely return a std::unique_ptr<QTimer>.
Just do a direct cast:
void Pool::timerDeleted(QObject *object) {
QTimer *theTimer = (QTimer*)object; //qobject_cast doesn't work here
//we are sure that only a timer can be a sender
timers.removeOne(theTimer);
}
You could base your list on QPointer instead of raw pointers. I.e. write
QList<QPointer<QTimer>> timers;
Now when one of the timers in the list goes away, the corresponding entry in the list will automagically be cleared. It will not be removed, though! But when you access the timer via your getTimer() method, an entry whose timer has been deleted will now return a nullptr (and not a dangling pointer).
And yes, QWidget emits destroyed() in its own destructor. This is why you see a real QWidget in that case. Everybody else uses QObject's implementation.
The other way around is safe. Cast QTimer * to QObject * instead:
void Pool::timerDeleted(QObject *object) {
const auto it = std::find_if(timers.begin(), timers.end(), [object](QTimer *timer) {
return static_cast<QObject *>(timer) == object;
});
Q_ASSERT(it != timers.end());
timers.erase(it);
}
Or use erase_if(QList &list, Predicate pred) introduced in Qt 6.1.

Qt 5.3 Signals and Slots, Simple Function and Lambda Expression

I tried to Write a program using Qt 5.3 and I try to using signals and slots as practice. I wrote the following code (part of the code) :
void exitToWin()
{
exit(0);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QMessageBox EndBox;
QObject::connect((EndBox.button(QMessageBox::Ok)),SIGNAL(clicked()),exitToWin);
w.show();
EndBox.show();
return a.exec();
}
I even change the declaration of the function to static and I checked the expression with parentheses and without them while I am writing the connect command. but although what Qt documented and what its IDE guided to. also I read here and I tested it.
Moreover I tried with lambda expression as below:
QObject::connect((EndBox.button(QMessageBox::Ok)),SIGNAL(clicked()),[=](){
exit(0);
});
but still I receive errors indicate "No matching function call".
And after all I have to say that I am using Microsoft Windows 7.
This works on Qt 5.3:
#include <QtWidgets>
void exitToWin()
{
exit(0);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QMessageBox endBox;
endBox.addButton(QMessageBox::Ok); // (2)
endBox.connect(endBox.button(QMessageBox::Ok),
&QAbstractButton::clicked, exitToWin); // (1)
/* This works, too:
endBox.connect(endBox.button(QMessageBox::Ok),
&QAbstractButton::clicked,
[] () { exit(0); });
*/
w.show();
endBox.show();
return a.exec();
}
Here's why:
(1) You can use endBox's QObject to do the connection between the QAbstractButton's clicked signal and your exitToWin simple function. You also can't connect a SIGNAL to a simple function or a lambda, so we use the member function variety, instead.
(2) endBox doesn't actually get an OK button by default. When you mention it on line (1) in your code, it creates it, but not in time (apparently) to pass the pointer back to connect, so we create it first here.
Your code won't work for two reasons:
Firstly, QMessageBox does not have such a signal. See the documentation for the signals it does have.
Secondly, when making connections from a signal to a slot (or lambda function), you must define the function signatures, not specific values.
If a signal can pass a variety of values and you only want your slot to perform a certain function on a selection of those values (in this case, only if the value QMessageBox::Ok is passed) it is up to the slot to interrogate the values, not the connect statement.
Since the connect() method is from QObject it has to be called from a QObject child containing the Q_OBJECT macro in its declaration. Running qmake prepare the class to send signals and receive slots.

QEventLoop for synchronous wait for signal

I'm using Qt5, QCoreApplication.
In order to allow for readable and easy to maintain code, I need to write a blocking method in a class/thread A that will emit a signal, connected to a slot in a different thread B, and then wait for an answer or a timeout to occur asynchronously in thread B.
I have first been thinking about what felt like a natural solution: let thread B reply with a signal connected to a slot in thread A, and somehow wait for it. It seems QEventLoop can do that for me. But I keep reading contradictory statements: that's the pattern but avoid it if you can :-).
I'm pretty sure I could achieve my purpose by blocking A on a 0 QSemaphore that B would release when ready. The code would probably not be much more complex that way.
What do you experienced Qt developers think?
Is there a good solution or do you find some symptoms of flawed analysis in my description (i.e. do you think I should never ever need to do something like that? :-))?
The key ingredient you can leverage is the Qt::BlockingQueuedConnection.
This connection type lets you pass return value from a slot. You can use it in a signal-slot connection. You can also directly invoke the slot without using a signal through the QMetaMethod::invoke / QMetaObject::invokeMethod mechanism.
#include <QDebug>
#include <QThread>
#include <QCoreApplication>
class Master : public QObject {
Q_OBJECT
public:
Q_SIGNAL bool mySignal();
Q_SLOT void process() {
if (mySignal()) { // this can be a blocking call
qDebug() << "success!";
}
thread()->quit();
}
};
class Slave : public QObject {
Q_OBJECT
public:
Q_SLOT bool mySlot() {
// do whatever processing is needed here
// It's OK to call QCoreApplication::processEvents here
return true;
}
};
int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
QThread masterThread, slaveThread;
Master master;
Slave slave;
master.moveToThread(&masterThread);
slave.moveToThread(&slaveThread);
slave.connect(&master, SIGNAL(mySignal()), SLOT(mySlot()),
Qt::BlockingQueuedConnection);
masterThread.start();
slaveThread.start();
QMetaObject::invokeMethod(&master, "process");
masterThread.wait();
slaveThread.quit();
slaveThread.wait();
return 0;
}
#include "main.moc"
if you just want to emit a signal in your thread, which means your main thread will have a slot to connect you thread signal, it is simple, just emit it.
but if you want a slot in your thread, and receive signal and so something in your thread, you have to use QEventloop in you run method.
usually, I will just use QThread::wait to wait for other thread end.
be careful here, some Qt objects cannot work across the thread like QSql* and QTcpSocket....

Can you change the queue size of a Qt connection? [duplicate]

This question already has answers here:
How to Compress Slot Calls When Using Queued Connection in Qt?
(8 answers)
Closed 8 years ago.
In Qt you can connect two objects by setting up a signal in one object a slot in the other and then connecting them using "connect()".
Now by emitting a signal in one object it is sent to the second object. I have a system that takes user inputs and if there are too many user inputs I want my "queue" to fill up and not accept any more inputs.
I could implement a reply mechanism on the receiving object, but I want to know if we can make a queue size of (for example) 1. So only one message will be handled, and any new emittions are simply chucked away until the "pipe" is has space.
Is this possible in Qt?
In my case the two objects are in different threads and have a queued connection (if that makes any difference)...
MainWindow::MainWindow()
{
// Make object 1, stick it in another thread
MyObjType1 *obj1 = new MyObjType1();
anotherThread = new QThread; // anotherThread is type QThread *
obj1->moveToThread(anotherThread);
anotherThread->start();
// Make object 2, connect a signal to obj1
MyObjType2 *obj2 = new MyObjType2();
connect(obj2, SIGNAL(obj2Signal(int), obj1, SLOT(obj1Slot(int), Qt::QueuedConnection);
// Hammer obj1 with signals to its queue
for (int i = 0; i < 100000; i++)
{
emit obj2->obj2Signal(i);
}
}
So the idea would be that obj1 gets lots of signals, it handles the first one, and somehow throws the others away until it finishes, then takes on the next one that is emitted.
With a queued connection, for each slot connected to a signal there is a QMetaCallEvent posted to the connected slot object's event queue. The events are delivered when the event loop runs. The code below outputs:
about to emit
done emitting
in aSlot()
class MyObject {
Q_OBJECT
Q_SIGNAL void aSignal();
Q_SLOT void aSlot() { qDebug() << "in aSlot()"; }
public:
MyObject(Qt::ConnectionType conn = Qt::AutoConnection) {
// QObject::connect() defaults the connection type to Qt::AutoConnection,
// we merely duplicate this behavior.
connect(this, SIGNAL(aSignal()), SLOT(aSlot()), conn);
qDebug() << "about to emit";
emit aSignal();
qDebug() << "done emitting";
}
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
MyObject obj(Qt::QueuedConnection);
QCoreApplication::processEvents();
return 0;
}
The problem can now be reformulated to: How to force removal of duplicate QMetaCallEvent events from the event queue? This is known as event compression. I have already provided a canonical answer to that question. For user input, you want the most recently emitted signal to be retained, not the oldest one, but I've implemented both behaviors in the answer code.
Using the code from my answer, your example merely needs the following in the main() function:
int main(int argc, char ** argv) {
CompressorApplication<QApplication> app(argc, argv);
app.addCompressedSignal(MyObjType2::staticMetaObject.method(MyObjType2::staticMetaObject.indexOfSignal("obj2Signal(int)")));
MainWindow w;
w.show();
return app.exec();
}
Note: If one were connecting objects with the default Qt::AutoConnection and the objects were in the same thread, then the concept of a queue wouldn't apply at all. The slot is called before the signal function returns and nothing needs to be queued! The code below will output:
about to emit
in aSlot()
done emitting
// MyObject as above
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
MyObject obj;
return 0;
}