I want an simple and clear example of how to do the signal and slot mechanism in queued connection.
Take the below line as example. Think that obj1 is backend functionality object emitting signal asynchronously from another thread and is connected to a slot in GUI ( main thread):
connect(obj1, SIGNAL(Mysignal(vector<mystruct> )), this, slot(myslot(vector <mystruct>)))
I have read that you have to register the types(meta types).
Please give a clear, simple and ready to use code lines for the above example that I would need, so that errors during run time like vector, my struct or string not defined, etc.. I don't face.
Also, is there a better way to handle this like sending pointers like:
connect(obj1, SIGNAL(Mysignal(obj2 *)), this, slot(myslot(obj2 *)))
Obj2 contains the vector of mystruct. Will i still need to register the obj2 with those metatypes?
If somebody has experience in this, please share all your good practices and simple code snippets, I am new to the queued connections with arguments. Please help.
If you want a queued connection, you need to call connect with a 5. parameter Qt::QueuedConnection. Otherwise, you get a direct connection inside the thread where you sent the signal from. Edit: See Tobys comment below.
You must wrap a QVector<> into a typedef, otherwise registering will not work (bug? in Qt from the stoneage). Also do not use references to your typedef, will not work either.
Header
typedef struct {
int a;
int b;
} mystruct;
typedef QVector<mystruct> myvector;
Q_DECLARE_METATYPE(myvector);
Source
void MainWindow::test()
{
qRegisterMetaType<myvector>();
connect(this, SIGNAL(sigRec(myvector)), SLOT(slotRec(myvector)), Qt::QueuedConnection);
mystruct x = {1,2};
myvector v;
v.append(x);
emit sigRec(v);
}
void MainWindow::slotRec(myvector s)
{
}
Related
So what I am trying to do is use Qt signals and slots to pass around an image through a smart_ptr so that it will delete itself when everything that needs to use the data is done accessing it.
Here is the code I have:
Class A, inherits QObject:
signals:
void newImageSent(boost::shared_ptr<namespace::ImageData> &image);
Class B, inherits QObject:
public slots:
void newImageRecieved(boost::shared_ptr<namespace::ImageData> &image)
{
// Manipulate Image
}
Connection Code:
QObject::connect(classAPtr.get(),
SIGNAL(newImageSent(boost::shared_ptr<namespace::ImageData>)),
classBPtr.get(),
SLOT(newImageRecieved(boost::shared_ptr<namespace::ImageData>)),
Qt::QueuedConnection);
When I try to do the connection is always returns false though, so is there something I am missing?
In a queued connection the signal is queued in the event loop and its parameters are copied.
Therefore the slot is not directly executed.
To make copying possible you have to register the type via qRegisterMetaType, see also here.
Since you are using shared pointers easiest solution would be to transmit them by value, then you would not have to bother with the references as Frank Osterfeld pointed out.
The way you create the connection is string based and as result is easy to get wrong, especially when namespaces are involved.
Using typedef would ease the pain a little and make it easier to spot errors.
For example you could do
typedef boost::shared_ptr<namespace::ImageData> ImageDataPtr;
and use ImageDataPtr from then on.
Especially on registering the type as meta type which you have to do since you are using a queued connection.
If you are using Qt5 then you can rely on the new connection syntax which ensures correctness during compilation as it does not rely on string comparisons:
QObject::connect(classAPtr.get(), &A::newImageSent,
classBPtr.get(), &B::newImageRecieved,
Qt::QueuedConnection);
I connect a slot with a signal. But now I want to disconnect them temporarily.
Here is part of my class declaration:
class frmMain : public QWidget
{
...
private:
QTimer *myReadTimer;
...
private slots:
void on_btnDownload_clicked();
...
};
In the constructor of frmMain, I connect myReadTimer with a slot so that ReadMyCom will be called every 5 seconds:
myReadTimer=new QTimer(this);
myReadTimer->setInterval(5000);
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
But, in slot on_btnDownload_clicked. I don't want myReadTimer to emit any signal in on_btnDownload_clicked's scope. So I want to disconnect them at the beginning of on_btnDownload_clicked and reconnect them in the end. Like this:
void frmMain::on_btnDownload_clicked()
{
//some method to disconnect the slot & singal
...//the code that I want myReadTimer to leave me alone
//some method to reconnect the slot & singal
}
I searched in Stackoverflow and got some answer like call the QObject destructor. But I don't know how to use it.
I also tried to use disconnect, like:
QMetaObject::Connection myConnect;
myConnect=connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
...
disconnect(& myConnect);
But it still not work. So could any one help me how to do this?
There is a very nice function in QObject that comes in handy every now and again: QObject::blockSignals()
Here's a very simple fire-and-forget class that will do what you want. I take no credit for it's design, I found it on the internet somewhere a long time ago. Be careful though, it will block all signals to all objects. If this is not what you want, you can modify the class to suit your needs.
class SignalBlocker{
public:
SignalBlocker(QObject *o): object(o), alreadyBlocked(object->signalsBlocked()){
if (!alreadyBlocked){
object->blockSignals(true);
}
}
~SignalBlocker() {
if (!alreadyBlocked){
object->blockSignals(false);
}
}
private:
QObject *object;
bool alreadyBlocked;
};
Usage, in your case, becomes trivial
void frmMain::on_btnDownload_clicked()
{
SignalBlocker timerSignalBlocker(myReadTimer);
...//the code that I want myReadTimer to leave me alone
// signals automatically unblocked when the function exits
}
UPDATE:
I see that from Qt 5.3, a very similar class has been offically added to the API. It does a similar job as the one above with a slightly bigger feature-set. I suggest you use the official QSignalBlocker class instead in order to keep your codebase up-to-date with any API changes.
Usage, however, remains exactly the same.
Disconnect/reconnect syntax
There are many ways to call disconnect, depending on exactly what you want disconnected. See the QObject documentation page for an explanation of how they work.
Here's an example using 0 to mean "disconnect all slots."
void frmMain::on_btnDownload_clicked()
{
// disconnect everything connected to myReadTimer's timeout
disconnect(myReadTimer, SIGNAL(timeout()), 0, 0);
...//the code that I want myReadTimer to leave me alone
// restore the connection
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
}
Or you can specify the exact signal-slot pair to disconnect by copying your 'connect' syntax, like this:
disconnect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
Stopping the timer
Since you're working with a timer, this may be simpler:
void frmMain::on_btnDownload_clicked()
{
// stop the timer (so you won't get any timeout signals)
myReadTimer->stop();
...//the code that I want myReadTimer to leave me alone
// restart the timer (using whatever interval was set previously)
myReadTimer->start();
}
Differences from your original approach:
Since you're stopping and restarting the timer, the next time it fires will be interval after your slot function finishes.
Do you need to do anything special at all?
In a single-threaded Qt application, if you're already handling a signal, another signal won't "jump in the middle" of that code. Instead it'll be queued up as an even to handle immediately after the current slot returns.
So perhaps you don't need to stop or disconnect your timer at all.
Differences from your original approach:
If on_btnDownload_clicked takes a while to execute, you might have multiple ReadMyCom events queued up after on_btnDownload_clicked completes. (Note that at this point you'd have an operation that basically "locks up" your GUI for a while anyway; it may make more sense to refactor the function or give it its own thread.)
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
Debugging signals and slots can be hard, because the debugger does not jump to the slots of a signal when it is emitted. What are some best practices for debugging Qt signals and slots?
In particular
How do I make sure connections are set up successfully?
When should I use signals and slots, when should I avoid them?
What are the most efficient debugging techniques from your experience?
There was a blog post written a while back called 20 ways to debug Qt signals and slots
It addresses I think #1 and #3 of your questions.
For #2, I don't think there is really a hard and fast reason to use or not use signals/slots, as they are a pretty core concept of the GUI framework. Signals are a perfect way to decouple the knowledge of one component to another, allowing you to design reusable widgets that simply declare state changes or notifications. It is also a very good way to communicate GUI changes from non-GUI thread loops, by emitting a signal that the main thread can see.
There might be times where what you really want instead of a signal/slot is to use events, such as when a parent widget should become the event filter for a number of child widgets. The children still do not need to know about the parent, and the parent gets a more direct event as opposed to a signal connection.
On the same topic of events, there are times where what you really want is a bubbling up of an event from child -> parent -> grandparent -> etc. Signals would make less sense here because they are not meant as a way to determine whether the proposed event should result in an action (they could be used this way obviously). Events allow you to check the current state, decide whether this widget should do anything, or otherwise bubble them up the chain for someone else to inspect.
There is a really fantastic answer about The Difference Between Signals/Slots and Events. Here is a good snippet:
You "handle" events
You "get notified of" signal emissions
What I like about that quote is that it describes the different need case. If you need to handle an action in a widget, then you probable want an event. If you want to be notified of things happening, then you probably want a signal.
In addition to what have been said, here are additional tricks.
If you use QTest for your unit tests, then you can pass -vs argument to the executable and all signals will be shown in the console.
I looked at how QTest works, and it registers callbacks that is triggered when signal and slots are executed using QSignalDumper class. However, this API is not exported and might break any time. Here is how I was able to hook on all signals and slots on Linux with Qt 5.10 using GCC.
// QSignalSpyCallbackSet is defined in qt5/qtbase/src/corelib/kernel/qobject_p.h
struct QSignalSpyCallbackSet
{
typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
BeginCallback signal_begin_callback,
slot_begin_callback;
EndCallback signal_end_callback,
slot_end_callback;
};
typedef void (*register_spy_callbacks)(const QSignalSpyCallbackSet &callback_set);
static void showObject(QObject *caller, int signal_index, const QString &msg)
{
const QMetaObject *metaObject = caller->metaObject();
QMetaMethod member = metaObject->method(signal_index);
qDebug() << msg << metaObject->className() << qPrintable(member.name());
}
static void onSignalBegin(QObject *caller, int signal_index, void **argv)
{
showObject(caller, signal_index, "onSignalBegin");
}
static void onSlotBegin(QObject *caller, int signal_index, void **argv)
{
showObject(caller, signal_index, "onSlotBegin");
}
int main(int argc, char *argv[])
{
static QSignalSpyCallbackSet set = { onSignalBegin, onSlotBegin, 0, 0 };
QLibrary qtcore("libQt5Core");
register_spy_callbacks reg = (register_spy_callbacks)qtcore.resolve("_Z32qt_register_signal_spy_callbacksRK21QSignalSpyCallbackSet");
if (reg) {
reg(set);
}
...
}
I believe that Qt should expose that API, because we could use it for so many things beyond debugging, such as monitoring the time spent in a slot, get statistics, etc.
How do I make sure connections are set up successfully?
You will see warnings in the console output from your application for each failed connection.
When should I use signals and slots, when should I avoid them?
In my opinion, it's fine to use them any time you want to maintain separation of concerns in your class design. Your class can emit a signal that may or may not be answered by another class (or classes) completely unknown to your class. This keeps your coupling down.
What are the most efficient debugging techniques from your experience?
I can't really add anything more than what is said on this blog post. 20 ways to debug Qt signals and slots
Regarding #1, I'll just add another piece of information that I didn't see mentioned above or in the referenced blog post.
From the documentation on QObject::connect():
Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns true if the connection succeeds; otherwise returns false.
I prefer asserting the return value of my connection to make sure the connection succeeded, especially because not all Qt programs will have console output. This also leads to more easily maintainable code, as it will catch changes made at a later date to either the signal or the slot, and force the programmer who made the changes to update the connections as well.
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.