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);
Related
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)
{
}
A simple question regarding the new signal/slot syntax in Qt5:
Are there still benefits for a Q_OBJECT-derived class to have public slots: sections declared?
Note: With the new syntax you're able to connect a signal to any public function of a class or directly implement a C++11 lambda (which can also call some member functions itself).
Qt's new signal/slot syntax
While the answers by vahancho and TheDarkKnight are valid: slots is not required for connections, but it makes the intent clearer and allows introspection. I think I should list some use cases where you do need slots.
First please note that you can use slots, Q_SLOTS, Q_SLOT or Q_INVOKABLE to make a function known to the meta object (introspection) system. Q_INVOKABLE has the advantage that it can be used on constructors.
And here are the use cases in no particular order:
Make your code works with Qt 4. Even if Qt 4 is not maintained I think some big company are still using it and it is fairly easy to make a library works with Qt 5 and Qt 4.
Make the function available in QML (and Qt Quick)
Make the function available in javascript (Qt Script, Qt WebEngine, etc.)
Make the function callable with QMetaObject::invokeMethod(). An overload that accepts functors will be available in Qt 5.10.
Make use of QMetaObject::connectSlotsByName(). Note that this function should not be used as it can be affected by object name collisions, but it is still the way the Qt widget designer connects the slots it creates.
Make your class instantiatable with QMetaObject::newInstance().
And every other use case that requires run-time introspection
you're able to connect a signal to any public function of a class or directly implement a C++11 lambda
Whilst this was made available in Qt 5, which allows for compile-time verification of the slot, as opposed to when using the SIGNAL and SLOT macros, it is no longer a requirement to declare a function as a slot to connect to it.
However, for clarity I still do, as it makes the intention of a class clearer for usage, when others come to using the class.
For example:
class Foo : public QObject
{
public:
Foo();
public slots:
void AddData();
private:
void CalculateStuff();
};
Just by looking at the class, we can assume that the function AddData is designed to be called via a signal; perhaps it executes on a separate thread.
public slots: etc. declarations still needed for moc introspection if you are going to use the "old" connection style. With the new syntax this declarations do not make any sense, because, as you also noticed, "slots" are called directly by function pointers. "Slots" may even be a non class member functions as well.
However, you still need to declare your signals under signals: section of your class declaration.
They're still needed for Qml, so that you can connect to C++ slots. However, if you want to call a C++ QObject member function, you can just declare it as Q_INVOKABLE. You don't need to make it a slot. Although using slots: might be more readable compared to using Q_INVOKABLE. Up to you.
They're also needed if you want Designer to see them. Designer has a "signal/slot" editor, and it will not list functions that are not in the slots: section. However, Designer still uses the old string-based syntax for signals and slots, so I wouldn't recommend using its signal/slot editor.
I'm a beginner in Qt and trying to understand the SIGNAL and SLOT macros. When I'm learning to use the connect method to bind the signal and slot, I found the tutorials on Qt's official reference page uses:
connect(obj1, SIGNAL(signal(int)), obj2, SLOT(slot()))
However, this also works very well:
connect(obj1, &Obj1::signal, obj2, &Obj2::slot)
So what exactly do the macros SIGNAL and SLOT do? Do they just look for the signal in the class the object belongs to and return the address of it?
Then why do most programmers use these macros instead of using &Obj1::signal since the latter appears to be simpler and you don't need to change the code if the parameters of the signal function change?
The use of the SIGNAL and SLOT macros used to be the only way to make connections, before Qt 5. The connection is made at runtime and require signal and slots to be marked in the header. For example:
Class MyClass : public QObject
{
Q_OBJECT
signals:
void Signal();
slots:
void ASlotFunction();
};
To avoid repetition, the way in which it works is described in the QT 4 documentation.
The signal and slot mechanism is part of the C++ extensions that are provided by Qt and make use of the Meta Object Compiler (moc).
This explains why signals and slots use the moc.
The second connect method is much improved as the functions specified can be checked at the time of compilation, not runtime. In addition, by using the address of a function, you can refer to any class function, not just those in the section marked slots:
The documentation was updated for Qt 5.
In addition, there's a good blog post about the Qt 4 connect workings here and Qt 5 here.
Addition to the first answer.
what exactly did the macro SIGNAL and SLOT do
Almost nothing. Look at the qobjectdefs.h:
# define SLOT(a) "1"#a
# define SIGNAL(a) "2"#a
It just adds 1 or 2. It means that next code is valid and works as expected:
QObject *obj = new QObject;
connect(obj,"2objectNameChanged(QString)",this,"1show()");//suppose this is a pointer to a QDialog subclass
obj->setObjectName("newNAme");
why do most programmers use these macros instead of using like
&Obj1::signal
Because these macros work not only in Qt5.
Because with these macros there is no complexity with overloaded
signals (it can make your code very dirty and it is really not a simple thing)
Because with new syntax you sometimes need to use specific
disconnects
More details here.
To complete TheDarkKnight's answer, it is an excellent practice to refactor legacy code that is using the old Qt 4 SIGNAL and SLOT macros to Qt 5's new syntax using function address.
Suddenly, connection error will appear at compile time instead of at runtime! It's very easy to make a Qt 4 connection error as any spelling mistake will result in such an error. Plus, the name of the function must be the fully qualified name, i.e preceded with the full namespace if any.
Another benefit is the ability to use a lambda for the slot function, which can reduce need of a named function if the slot body is trivial.
These macros just convert their parameters to signal/slot-specific strings. The Differences between String-Based and Functor-Based Connections can be found in the docs. In short:
String-based:
Type checking is done at Run-time
Can connect signals to slots which have more arguments than the signal (using default parameters)
Can connect C++ functions to QML functions
Functor-based:
Type checking is done at Compile-time
Can perform implicit type conversions
Can connect signals to lambda expressions
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.
I am relatively new to programming with Qt and had a question. Short version:
How do I inherit signals defined in superclasses?
I am trying to subclass someone else's nicely made QTWidgets to change some of the default behavior:
//Plot3D is a QWidget that defines a signal "rotationChanged"
class matLinePlot : public QObject, public Plot3D {
Q_OBJECT;
//etc...
public:
//etc...
//Catch Plot3D's signal "rotationChanged" and do some magic with it:
void initPlot(){
QObject::connect(this, SIGNAL(rotationChanged( double , double , double )),
this, SLOT(myRotationChanged(double, double, double)));
}
};
The problem is in the QObject::connect line. What I would like to do is connect the rotationChanged SIGNAL (from qwt3D_plot.h) to a local function/SLOT - "myRotationChanged". However whenever I do this, at run time I get:
Object::connect: No such signal matLinePlot::rotationChanged(double, double, double)
in C:...\matrixVisualization.h. Of course, I know that rotationChanged isn't in matrixVisualization.h - it's in qwt_plot3D.h, but I thought that since I inherit from Plot3D everything should be fine. But, now that I think about it, since SIGNAL and SLOT are macros, I assume MOC doesn't know/care about inheritance.
Which leads me to my question - since MOC and SIGNALS / SLOTS don't seem to know about inheritance etc: how can I subclass a widget defined somewhere else and get access to the widget's signals?
I have a lot of examples of how to use encapsulation to accomplish something like this, but I'm afraid I don't understand how to do this with inheritance.
Sorry if this is a ridiculous question - I feel like I'm missing something obvious.
I guess the problem is the multiple inheritance:
class matLinePlot : public QObject, public Plot3D
...
I assume that Plot3D is a subclass of QObject? In this case, you should do
class matLinePlot : public Plot3D
...
instead.
SIGNAL(x) and SLOT(x) are macros that generate string literals. At runtime, slots and signals are matched up using string compares of those generated literals.
(I would have added a comment to mdec's comment, but I don't have enough rep)
I believe that will work if the Plot3D::rotationChanged signal is public or protected. Are you sure the signal is not private?
Edit:
Although I could not find a specific reference, I'll have to conclude that signals are always public. At least a test I did here seemed to indicate that I could connect to a signal even if it was declared in the private section of a class.
I also verified that a signal declared in QObject could be connected using a subclass of QObject in the connect statement so signals are definitely inheritable. As I see in other answers and comments here, the issue must be elsewhere.
Incorrect -> see comments.
I'm using Qtopia at Uni and I believe I recall someone saying something about spacing in the SIGNAL and SLOT parameters for connect.
Try using
QObject::connect(this, SIGNAL(rotationChanged(double,double,double)),
this, SLOT(myRotationChanged(double,double,double)));
I know it doesn't seem intuitive, as C++ isn't sensitive to whitespace, however I believe it has something to do with some of the magic that Qtopia/QT uses when connecting signals and slots. This may only apply to Qtopia, or I may have heard wrong, but give it a try. Additionally are the signals public or protected and have you included the appropriate header files?