Passing arguments with signals and slots in qt - c++

I am new to qt and i have got a question.
I wanted to connect signals and slots.
QObject::connect(_Requests, SIGNAL(newJobsAvailable(const MyClass &)), _Object, SLOT(doSend(const MyClass &)));
The qt complains about not being able to queue MyClass and etc.
How do i declare it correctly with
qRegisterMetaType<const MyClass &>("const MyClass&");

If Qt complains about not being able to queue you class this means that, Qt is unable to copy and put inside QVariant object of your class.
This only means that only direct connection will work. What does it mean? If you are using default value of last argument in connect then connection will not work between threads!
Setting last argument of connect to Qt::DirectConnection should silence the warning, and value Qt::QueuedConnection will not work at all.
Another way to fix it is to register your type. But you should do this without any qualifiers!
qRegisterMetaType<MyClass>("MyClass");
If you are using Qt5 then consider use of Q_GADGET macro in MyClass (just put it in beginning of class definition and add header to HEADERS in pro file).

You need to make sure that MyClass has public default and copy constructors. Because the object might be copied, even if you declare signals and slots with const ref.
If for some reason copy is out of the question then pass pointer as suggested by ratchet

Related

Registering a Struct for use with Qt Queued Connections

I have an object in a worker thread that needs to pass data back to its controller in the main thread.
There's several fields to move, so I'd prefer to do this using a struct. The Qt docs make it clear that to use a custom type with Queued Connections, I need to use both Q_DECLARE_METATYPE and qRegisterMetaType.
The struct is declared in my worker class, which is inside a namespace. In the header, after the class declaration, outside the namespace, I've included Q_DECLARE_METATYPE(myNamespace::myWorkerClass::myStruct). I'm not sure where qRegisterMetaType belongs, so for the moment I've put it in the controller's constructor - qRegisterMetaType(myWorkerClass::myStruct).
(I've tried several other configurations as well, but they haven't helped).
In each case, the program compiles happily but fails to execute the slot from the signal, outputting QObject::connect: Cannot queue arguments of type 'myStruct'.
So it looks like there's something I'm not understanding. Any clues?
As documentation states:
To use the type T in queued signal and slot connections,
qRegisterMetaType() must be called before the first connection is
established.
So if you put the register in constructor, you have to instance your class once and then make the connection.
A common way to register the type is in main or with a static function register.
Solution 1:
somewhere.h
void registryCustonType()
{
qRegisterMetaType(myWorkerClass::myStruct);
// other registry for custom classes.
}
main.cpp
int main()
{
registryCustomTypes();
// ...
}
Solution 2:
mystruct.cpp
namespace {
static const bool reg = qRegisterMetaType(myWorkerClass::myStruct);
}
I usually use the latter, which allow me to not specify any register function explicitely.

Cannot connect signal from an outer shared library to overloaded slot of QWidget derived class

I try to connect the signal from an outer shared library to an overloaded slot of base QWidget class's slot.
Suppose this is an instance of a class derived from QWidget
class MyClass : public QWidget;
...
MyClass* this_instance = new MyClass;
I tried the following approach
connect(obj_from_sl, SIGNAL(signalFromSL()), this, SLOT(update());
// update() is QWidget's slot
// the "sl" suffixs stands for "shared library"
but it didn't work. I have got linker errors. I have searched and found out, that
it is impossible to connect signal from an outer shared library using SIGNAL/ SLOT macros inside the connect function. It might be possible if I use function pointers.
OK. Let's change the signature:
connect(obj_from_sl, &ClassFromSL::signalFromSL, this, &QWidget::update);
^ error comes here
and voilĂ 
cannot determine which instance of an overloaded function "QWidget::update" is intended.
Could anyone help me to solve this problem?
The QWidget::update() function has different arguments, so it requires explicit casting for the new signal/slot syntax use
connect(obj_from_sl, &ClassFromSL::signalFromSL, this, static_cast<void (QWidget::*) )>(&QWidget::update));

Connect to protected slot in derived class

This is how the declarations in the base class look:
protected:
void indexAll();
void cleanAll();
In the derived class the following does not compile:
indexAll(); // OK
connect(&_timer, &QTimer::timeout, this, &FileIndex::indexAll); // ERROR
connect(&_timer, SIGNAL(timeout()), this, SLOT(indexAll())); // OK
I would like to use the first variant of connect, since it does some compile time checks. Why is this returning the error:
error: 'void Files::FileIndex::indexAll()' is protected
void FileIndex::indexAll()
^
[...].cpp:246:58: error: within this context
connect(&_timer, &QTimer::timeout, this, &FileIndex::indexAll);
^
The 'old' style syntax works because signal emission runs through qt_static_metacall(..) which is a member of FileIndex and so has protected access.
The 'new' style syntax does work, but for this reason won't let you take the address directly of the parent class method. It will however take the 'inherited' address of indexAll(), so just change the code to:
connect(&_timer, &QTimer::timeout, this, &Derived::indexAll);
The first one is ruled by normal C++ accessibility rules. The QTimer::timeout signal call the FileIndex::indexAll over the provided function pointer directly. Of course, this is only possible when this function pointer is public (disregarding possible friend solutions). If you use function pointers you don't even need to mark the function as SLOT in the header file.
The second one is moc magic. Calls through the meta-object system. I never delved into this topic any deeper... it just worked. :-)
Ok, not the best explanation. If you want more info:
http://woboq.com/blog/new-signals-slots-syntax-in-qt5.html
http://woboq.com/blog/how-qt-signals-slots-work.html
http://woboq.com/blog/how-qt-signals-slots-work-part2-qt5.html
Good reads, but... only of interest if your are interested in the deeper workings of Qt. IMHO only necessary if you want to develop Qt itself.

Qt signals and slots: permissions

There are discrepancies between respected answers here on SO and the actual Qt docs.
I've read this question and I want some further clarification. Can anyone confirm:
A signal is always protected, therefore it can be emitted only by the class or any of its subclasses. I'm not sure this is true; the question above shows answers supporting this statement. But the Qt docs say: Signals are public access functions and can be emitted from anywhere, but we recommend to only emit them from the class that defines the signal and its subclasses. So which is it?
Slots are just functions, and thus may be public, private or protected. Obviously an outside class will have the ability to control if your class connects one of its own signals to one of its own slots if the slot is public. However, again the SO information differs from the docs, which say: a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class. This means that private is not honored by the signal/slot mechanism?
The words public, private, protected have no use with working with the signal keyword
The emitted signal is always available to all other classes, that is, any other class may always connect to that signal (regardless of its permission to emit the signal).
Despite that all signals are viewable to by all classes, you could still have two classes with signals of the same name since the connect function takes the class name as a signal prefix (i.e. SomeClass::itsSignal)
Signals are protected in Qt4 but are public in Qt5, thus the contradictory information.
Slots are functions and public/protected/private is honored when calling them as such, when connecting to a signal, the metaobject system ignores it though.
As signals is defined as public:, prepending them with e.g. private leads
to:
private:
public: //signals:
void theSignal();
Thus it's without effect.
All classes can be connected to any signal, correct. Signals are part of the public API in that regard.
Having identical signal signatures is not a problem. The context is defined by the object specified as sender.
Using old-style connect:
Apple *apple ... Orange* orange
connect(apple, SIGNAL(changed()), this, SLOT(appleChanged()));
connect(orange, SIGNAL(changed()), this, SLOT(orangeChanged()));
The signal is specified as string here (without the class name in it), but as apple and orange have only one signal changed() each and the lookup is done in the metaobject of the QObject instance, which exists one per class (not instance), they cannot collide.
Qt 5 version with compile-time checking:
connect(apple, &Apple::changed, this, &MyReceiver::appleChanged);
Here one must specify a function, so depending on the scope, one must specify a class name (and maybe namespaces). As an ambiguous function name wouldn't be valid C++ and thus not compile, so one is safe here.
Take a look at qobjectdefs.h (QT5.0+). In there are defined the moc macros
# define signals public
As you can see the macros used in header files for signals are defined as public. As for the explicit statet public,private,protected directives, these are ignored in the signals section. Prior 5.0 versions of QT have signals defined as protected. Those were still available for connections using the SIGNAL() macro.
The slots macro
# define slots
is defined as an empty macro and therefore can be used with:
public slots:
private slots:
protected slots:
The method visibility is used for direct method calls, so private/protected cannot be called from foreign classes directly.
Using the a connect statement still works independently from the visibility. This is the intended behaviour and is implemented in the moc-generated code.
If i remember correctly in earlier versions of Qt a slot was also public automatically, but i did not find a reference for that now.
Any other class can connect to a signal from a foreign class, as long the Q_OBJECT macro is given in the class and the foreign class is known (header included). Since signals are defined per-class it is perfectly legal to have the same signal in different classes. This is also pretty convenient, for example have a signal sendInfo(QString) in all classes makes it easier to remember. The Q_OBJECT macro makes the moc to create code needed to connect signals to slots independent to visibility.
The emitted signal is always available to all other classes, that is, any other class may always connect to that signal (regardless of its permission to emit the signal).
In Qt5, this isn't necessarily true. A signal can be defined with QPrivateSignal as its final argument, and in that case, only the object which declared the signal would be able to connect to it.

Signals and Slots - Passing Data

Im trying to connect a signal to a slot and pass through a vector but im not having much luck.
res = QObject::connect(storePayments, SIGNAL(existingPurchasesResponseSuccess(std::vector<QString>)), this, SLOT(RefreshPurchasesSuccess(std::vector<QString>)));
Slot:
void RefreshPurchasesSuccess(std::vector<QString>);
void Store::RefreshPurchasesSuccess(std::vector<QString> previousPurchasesArray)
{
//do something
}
Signal:
void existingPurchasesResponseSuccess(std::vector<QString>);
vector<QString> previousPurchasesArray;
emit existingPurchasesResponseSuccess(previousPurchasesArray);
It says the signal/slot is not defined, but when I take out the vector it works, so it must be something wrong with that. Am I defining it wrong?
Thanks
If you use custom structure like std::vector<QString> you must declare and register metatype
Q_DECLARE_METATYPE(std::vector<QString>)
"Ideally, this macro should be placed below the declaration of the class or struct. If that is not possible, it can be put in a private header file which has to be included every time that type is used in a QVariant." -- Qt documentation on Q_DECLARE_METATYPE
For queued connections you may need qRegisterMetatype
qRegisterMetaType<std::vector<QString> >();
qRegisterMetaType can be called for example in main() even before QApplication::exec().
Also remember that you must use Q_OBJECT macro if your class declares any signals or slots.
"The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system."
If you have no reason to use std::vector<QString> then it would be much simpler to use QStringList, which is already known to Qt's meta-object system, provides many convenient methods to manipulate its content and as a standard Qt type will fit to non-yours slot definitions.