My signal / slot connection does not work - qt

I repeatedly see people having problems with slots not being called. I would like to collect some of the most common reasons. So maybe I can help people and avoid a lot of redundant questions.
What are reasons for signal / slot connections not working? How can such problems be avoided?

There are some rules that make life with signals and slots easier and cover the most common reason for defective connections. If I forgot something please tell me.
1) Check the debug console output:
When execution errors occur, the debug output can show you the reason.
2) Use the full signature of signal and slot:
Instead of
connect(that, SIGNAL(mySignal), this, SLOT(mySlot));
write
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
and check your spelling and capitalization.
3) Use existing overloads:
Carefully check if you are using the desired overloads of signal and slot and if the overloads you used actually exist.
4) Your signal and slot must be compatible:
This especially means the parameters must be of the same type (references are tolerated) and have the same order.
Compile-time syntax also needs the same number of parameters. Old runtime syntax allows connecting signals to slots with less parameters.
5) Always check return value of connect method (programmers should never ignore return values):
Instead of
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
always use something like
bool success = connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
Q_ASSERT(success);
Or if you like throw an exception or implement full error handling. You may also use a macro like that:
#ifndef QT_NO_DEBUG
#define CHECK_TRUE(instruction) Q_ASSERT(instruction)
#else
#define CHECK_TRUE(instruction) (instruction)
#endif
CHECK_TRUE(connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))));
6) You need an event loop for queued connections:
I.e. when ever you connect signals/slots of two objects owned by different threads (so called queued connections) you need to call exec(); in the slot's thread!
The event loop also needs to be actually served. Whenever the slot's thread is stuck in some kind of busy loop, queued connections are NOT executed!
7) You need register custom types for queued connections:
So when using custom types in queued connections you must register them for this purpose.
First declare the type using the following macro:
Q_DECLARE_METATYPE(MyType)
Then use one of the following calls:
qRegisterMetaType<MyTypedefType>("MyTypedefType"); // For typedef defined types
qRegisterMetaType<MyType>(); // For other types
8) Prefer new compile time syntax over old run-time checked syntax:
Instead of
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
use this syntax
connect(that, &ThatObject::mySignal, this, &ThisObject::mySlot));
which checks signal and slot during compile time and even does not need the destination being an actual slot.
If your signal is overloaded use the following syntax:
connect(that, static_cast<void (ThatObject::*)(int)> &ThatObject::mySignal), this, &ThisObject::mySlot); // <Qt5.7
connect(that, qOverload<int>::of(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++11
connect(that, qOverload<int>(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++14
Starting with Qt5.14, overloaded signals are deprecated. Disable deprecated Qt features to get rid of the above shenanigans.
Also do not mix const/non-const signals/slots for that syntax (normally signals and slots will be non-const).
9) Your classes need a Q_OBJECT macro:
In classes where you are using "signals" and "slots" specifications you need to add a Q_OBJECT macro like this:
class SomeClass
{
Q_OBJECT
signals:
void MySignal(int x);
};
class SomeMoreClass
{
Q_OBJECT
public slots:
void MySlot(int x);
};
This macro adds necessary meta information to the class.
10) Your objects must be alive:
As soon as either the sender object or the receiver object is destroyed, Qt automatically discards the connection.
If the signal isn't emitted: Does the sender object still exist?
If the slot isn't called: Does the receiver object still exist?
To check the lifetime of both objects use a debugger break point or some qDebug() output in the constructors/destructors.
11) It still does not work:
To do a very quick and dirty check of your connection emit the signal by your self using some dummy arguments and see if it is called:
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
emit that->mySignal(0); // Ugly, don't forget to remove it immediately
Finally of course it is possible that the signal simply is not emitted. If you followed the above rules, probably something is wrong in your program's logic. Read the documentation. Use the debugger. And if there is now other way, ask at stackoverflow.

In my practice, I have encountered cases of incorrectly overriding eventFilter in the object receiving the signal. Some novice programmers forget to return "false" at the end of function. And thus do not allow the MetaCall event to pass to the receiving object. In this case, the signal is not processed at the receiving object.

Short answer
You (almost) don't have to worry about that anymore. Always use the QMetaMethod/Pointer to member prototype of connect, as it will fail at compile time if the signal and slot are not compatible.
connect(sourceObject, &SourceClass::signal, destObject, &DestClass::slot);
This prototype will only fail at runtime if the sourceObject or destObject is null (which is to be expected). But argument incompatibility will show up during compilation
Only rare situations require the older SIGNAL/SLOT literal-based syntax, so this should be your last resort.
Compatibility
The signatures are compatible if the following conditions are met:
You are connecting a signal to a slot or a signal
The destination signal/slot has the same number or less arguments than the source signal
Arguments of the source signal can be implicitly converted to the corresponding argument (matched in order) in the destination signal/slot, if used
Examples
OK - signalA(int, std::string) => signalC(int, std::string)
Note that we are connecting to a signal
OK - signalA(int, std::string) => slotB(int, std::string)
OK - signalA(int, std::string) => slotB(int)
String parameter ignored
OK - signalA(int, std::string) => slotB()
All parameters ignored
OK - signalA(int, const char*) => slotB(int, QString)
Implicitely converted with QString(const char*)
Fails - signalA(int, std::string) => slotB(std::string)
int not implicitely convertible to std::string
Fails - signalA(int, std::string) => slotB(std::string, int)
Incorrect order
Fails - signalA(int, std::string) => slotB(int, std::string, int)
Too many arguments on the right side

Related

What is the functional difference between these two qt signal-slot connections?

I'm using Qt 5.9.2 with Visual Studio 2015 and QtDesigner for programming a Windows GUI application. I tried connecting one of my actions via the following call:
connect(ui.myAction, &QAction::triggered, memberPtrToObjX_, &ClassX::Run);
However ClassX::Run is not always triggered after clicking on myAction in the menubar. Investigating into this problem, I figured, that the same signal-slot connection using lambda syntax works:
connect(ui.myAction, &QAction::triggered, [this](bool run) { memberPtrToObjX_->Run(run); });
I'm pretty sure, that both calls are syntactically correct. Besides both calls return a valid QMetaObject::Connection, if I save the return value and check with operator bool().
Obviously I could just stick with the working lambda-version, but I'm confused and would prefer knowing the reason behind my "solution". Is there any functional difference between these two calls, that explains the different behaviour?
The two calls of QObject::connect() (exposed by the OP) behave differently in the case that this->memberPtrToObjX_ is modified after the call of connect().
The first
connect(ui.myAction, &QAction::triggered, memberPtrToObjX_, &ClassX::Run);
calls
QMetaObject::Connection QObject::connect( const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection).
Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns a handle to the connection that can be used to disconnect it later.
Hence, the current pointer in this->memberPtrToObjX_ is connected as signal receiver. If this->memberPtrToObjX_ is modified after connect() this doesn't have any effect to the signal connection.
The second
connect(ui.myAction, &QAction::triggered, [this](bool run) { memberPtrToObjX_->Run(run); });
calls
QMetaObject::Connection QObject::connect( const QObject *sender, PointerToMemberFunction signal, Functor functor).
Creates a connection from signal in sender object to functor, and returns a handle to the connection.
Hence, the (functor behind the) lambda is connected as receiver. The lambda resolves the pointer in this->memberPtrToObjX_ at the time it is executed i.e. when the signal is triggered.
The second difference (which originally was uncovered in the comment of G.M.) is the connection type:
The first version uses the default value Qt::AutoConnection (as it is not defined explicitly). The version with the lambda uses always Qt::DirectConnection instead.
The difference appears if the pointee in this->memberPtrToObjX_ does not "live" in the same thread. In this case, the Qt::AutoConnection is resolved to Qt::QueuedConnection instead of Qt::DirectConnection.
I assumed that the pointee in this->memberPtrToObjX_ would "live" in the same QThread. If not, the second version (with the lambda) becomes very questionable as it calls the a member function of the object "living" in a different thread (where it is hard to tell what that thread is doing at this time). This only seems to work better but is very possibly a "time bomb".

When Qt-5 will fail the connect

Reading Qt signal & slots documentation, it seems that the only reason for a new style connection to fail is:
"If there is already a duplicate (exact same signal to the exact same slot on the same objects), the connection will fail and connect will return false"
Which means that connection was already successful the first time and does not allow multi-connections when using Qt::UniqueConnection.
Does this means that Qt-5 style connection will always success? Are there any other reasons for failure?
The new-style connect can still fail at runtime for a variety of reasons:
Either sender or receiver is a null pointer. Obviously this requires a check that can only happen at runtime.
The PMF you specified for a signal is not actually a signal. Lacking proper C++ reflection capabilities, all you can do at compile time is checking that the signal is a non-static member function of the sender's class.
However, that's not enough to make it a signal: it also needs to be in a signals: section in your class definition. When moc sees your class definition, it will generate some metadata containing the information that that function is indeed a signal. So, at runtime, the pointer passed to connect is looked up in a table, and connect itself will fail if the pointer is not found (because you did not pass a signal).
The check on the previous point actually requires a comparison between pointers to member functions. It's a particularly tricky one, because it will typically involve different TUs:
one is the TU containing moc-generated data (typically a moc_class.cpp file). In this TU there's the aforementioned table containing, amongst other things, pointers to the signals (which are just ordinary member functions).
is the TU where you actually invoke connect(sender, &Sender::signal, ...), which generates the pointer that gets looked up in the table.
Now, the two TUs may be in the same application, or perhaps one is in a library and the other in your application, or maybe in two libraries, etc; your platform's ABI starts to get into play.
In theory, the pointers stored when doing 1. are identical to the pointers generated when doing 2.; in practice, we've found cases where this does not happen (cf. this bug report that I reported some time ago, where older versions of GNU ld on ARM generated code that failed the comparison).
For Qt this meant disabling certain optimizations and/or passing some extra flags to the places where we know this to happen and break user software. For instance, as of Qt 5.9, there is no support for -Bsymbolic* flags on GCC on anything but x86 and x86-64.
Of course, this does not mean we've found and fixed all the possible places. New compilers and more aggressive optimizations might trigger this bug again in the future, making connect return false, even when everything is supposed to work.
Yes it can fail if either sender or receiver are not valid objects (nullptr for example)
Example
QObject* obj1 = new QObject();
QObject* obj2 = new QObject();
// Will succeed
connect(obj1, &QObject::destroyed, obj2, &QObject::deleteLater);
delete obj1;
obj1 = nullptr;
// Will fail even if it compiles
connect(obj1, &QObject::destroyed, obj2, &QObject::deleteLater);
Do not try to register pointer type. I've used the macro
#define QT_REG_TYPE(T) qRegisterMetaType<T>(#T)
with pointer type CMyWidget*, that was the problem. Using the type directly worked.
No it's not always successful. The docs give an example here where connect would return false because the signal should not contain variable names.
// WRONG
QObject::connect(scrollBar, SIGNAL(valueChanged(int value)),
label, SLOT(setNum(int value)));

QT - Understanding following lambda expression for a SLOT

I am currently trying to understand the new QT5 signal/slot syntax
connect(sender, &Sender::valueChanged, [=](const QString &newValue) {
receiver->updateValue("senderValue", newValue);
});
Now my question is where is the address of the receiver SLOT in the above expression ? I wanted to know this because what happens if a signal is in threadA and the slot is in thread B and I wanted it to be a queued connection ?
A slot is a piece of code, it doesn't "live" in a thread - a thread might run it or not, but the code itself doesn't belong to any thread. (If the slot is a member function, then the Qt object defined as the receiver belongs to a Qt thread - that's a property of the object, not the function.)
In the code you have above, the compiler generates an object that:
captures receiver by value ([=])
has a function-call operator that can be called with a reference to a const QString.
That object is passed to connect along with the other two arguments. It's not a QObject, so it doesn't have an owning thread in the Qt sense. What you need to make sure of is that:
what receiver points to stays alive for as long as that signal is connected
receiver->updateValue(...) is thread-safe - it will be called in sender's context/thread.
If receiver->updateValue needs to be called in receiver's thread/context, then do not use that syntax for the connect call, use the one where you specify both sender and receiver, and the connection type.

Passing QModelIndex cross Thread queued connection

WMIQuery::wmiquery(WMI::WMITable* table, const QString& query, WMI::ProgressIndicator* progressIndicator)
This is the Function signature. and I am calling it through QtConcurrent::run
QFuture<quint32> future = QtConcurrent::run(WMI::WMIQuery::wmiquery, _table, query);
The architecture is quite simple.
Expected number of rows that will be returned by the query is known.
query is ran parallelly and on each record fetch a row is added to table: WMI::WMITable*
WMI::WMITable is a Simple QObject Table Data Structure .
it emits rowsAboutToBeInserted(QModelIndex, int, int) and rowsInserted(QModelIndex, int, int) upon row addition.
On the other hand ProgressIndicator in instantiated on main thread and the table is passed to its ctor . it gets the expected total number of rows from WMI::WMIQuery::wmiquery() through ProgressIndicator::setRecordCount(quint64 count).
it has a slot rowAdded() which emits the progress out of 100 by doing some simple mathematics. In its ctor it connects
connect(_table, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowAdded()));
What I think. as WMI::WMIQuery::wmiquery() i running on a different thread (on QThreadPool) this connection is a cross thread queued connection . am I correct ?
I am getting the following error at runtime
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registered using qRegisterMetaType().)
What should I do ? as my SLOT(rowAdded()) does not require the 3 arguments of SIGNAL(rowsInserted(QModelIndex,int,int)) should I make another signal like rowInserted() and emit it whenever I am emitting rowsInserted(QModelIndex,int,int) and use this SIGNAL instead for this coinnection
You may ask why I am using model like signals like rowsInserted(QModelIndex,int,int) in the table data structure. cause I do also have a model that is connected to this table. which will also be updated row by row. however I think that is immater in this regard.
Before emitting a signal across a thread boundary with a non-trivial argument type (like QModelIndex), you must first call this:
qRegisterMetaType<QModelIndex>("QModelIndex");
That prepares Qt to be able to emit the signal across a thread boundary.
Normally you would do this in main() or somewhere that only runs once, before calling emit, but after your QApplication has been instantiated.
This is only necessary for types that are non-trivial. For example, a signal like this would not require you to call qRegisterMetaType()
signals:
void mySignal(int foo, int bar);
But a signal like this does require qRegisterMetaType():
signals:
void mySignal(QModelIndex);
For more info, see the Qt docs here: http://doc.qt.nokia.com/latest/qmetatype.html#qRegisterMetaType
I know this is rather late, but I wanted to be sure someone mentioned it: QModelIndex is not meant to be queued, for the same reason that it's not meant to be stored and used later in other ways. That is, if the model changes before you use the QModelIndex, you will get undefined behavior. If you need queued events with model indices, you should probably use QPersistentModelIndex. Not really relevant to the original question, but may be of use to someone who lands here.

How does Qt implement signals and slots?

Can someone explain to me the basic idea of Qt signals&slots mechanism IMPLEMENTATION?
I want to know what all those Q_OBJECT macros do "in plain C++".
This question is NOT about signals&slots usage.
added:
I know that Qt uses moc compiler to transform Qt-C++ in plain C++.
But what does moc do?
I tried to read "moc_filename.cpp" files but I have no idea what can something like this mean
void *Widget::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_Widget))
return static_cast<void*>(const_cast< Widget*>(this));
return QDialog::qt_metacast(_clname);
}
Concerning the signals and slots, the Q_OBJECT macro adds a virtual function qt_metacall() declaration into the class’s declaration which is to be defined later by the the moc. (It also adds some declarations for conversion but that’s not too important here.)
The moc then reads the header file and when it sees the macro, it generates another .cpp file named moc_headerfilename.cpp with the definitions to the virtual functions and – you might have asked yourself why you can get away with mentioning the signals: in your header file without a proper definition – of the signals.
So, when a signal is called, the definition from the mocfile is executed and QMetaObject::activate() is called with the signal’s name and the signal’s arguments.
The activate() function then figures out which connections have been established and fetches the names for the appropriate slots.
Then it calls qt_metacall with the slot names and the arguments given to the signal and the metacall function delegates this with the help of a large switch—case statement to the real slots.
As there is no real runtime information possible in C++ concerning the actual names for the signals and slots, as has already been noticed, these will be encoded by the SIGNAL and SLOT macros to simple const char*s (with either "1" or "2" added to the name to distinguish signals from slots).
As is defined in qobjectdefs.h:
#define SLOT(a) "1"#a
#define SIGNAL(a) "2"#a
—
The other thing the Q_OBJECT macro does is defining the tr() functions inside your object which can be used to translate your application.
Edit
As you asked what the qt_metacast is doing. It checks whether an object belongs to certain class and if it does returns the pointer to it. If it doesn’t, it returns 0.
Widget* w = new Widget();
Q_ASSERT(w->qt_metacast("Widget") != 0);
Q_ASSERT(w->qt_metacast("QWidget") != 0);
Q_ASSERT(w->qt_metacast("QObject") != 0);
Q_ASSERT(w->qt_metacast("UnrelatedClass") == 0);
This is needed to provide some runtime reflection which is not possible otherwise. The function is called in QObject::inherits(const char *) for example and simply checks for inheritance.
Those macros do absolutely nothing "in plain C++", - they expand to empty strings (I think).
QT uses a meta-object compiler, that generates C++ code for Q_OBJECT-enabled classes (implementing the signals/slots you define, among other things).
You can read more about it in the official documentation.
The basic idea is that you can connect your objects allowing them to execute a method (slot) when a signal is done.
connect(pistol,SIGNAL(sigShoot()),runner,SLOT(slotRun()))
Doing the connection above, when the pistol emits the signal, the runner will execute its slot.
To do this, you have to declare your signals and slots in your respective classes.
Is the basic idea.
Good luck!

Resources