Can Qt signals be public or private? Can I create internal signals, which are seen only inside the class?
Update: I have a class with some internal signals. How can I make those signals invisible for other classes (encapsulation & information hiding)?
No. Signals cannot be public or private. Qt signals are protected class methods.
"signals" keyword is defined in qobjectdefs.h (line 69 as for Qt 4.6.1):
# define signals protected
UPDATE: signals are only protected upto and including all minor versions of Qt 4. From Qt 5.0 onwards they are public. See https://stackoverflow.com/a/19130831.
A common way, e.g. seen in kdelibs, is this:
Q_SIGNALS:
#ifndef Q_MOC_RUN
private: // don't tell moc, doxygen or kdevelop, but those signals are in fact private
#endif
void somePrivateSignal();
This makes the signal private, i.e. it can only be emitted by the class itself but not by its subclasses. To not make the "private:" overrule Q_SIGNALS (moc wouldn't see somePrivateSignal as signal then), it's inside Q_MOC_RUN, which is only defined when moc runs.
Edit: This approach doesn't work for the new-style connects introduced with Qt 5 (connect(a, &A::someSignal, b, &B::someSlot)), as they require the signal to be accessible.
Signals was protected in Qt4, in Qt5 they are public. Int Qt5 you can make them private by adding QPrivateSignal as the last argument. More on this: http://woboq.com/blog/how-qt-signals-slots-work-part2-qt5.html
Slots are simple methods which can be public, protected, or private.
As Andrei pointed it out, signal are only a redefinition of protected, meaning they can only be emitted by the class in which they are defined.
If you want to make a class emit a signal from anoter one, you have to add it a public method (or slot) like this one:
void emitTheSignal(...) {
emit theSignal(...);
}
Qt signals are public in the sense that any object can connect to any signal.
All the existing answers are incorrect.
A signal can be made private by adding a QPrivateSignal type to its definition as the last argument:
signals:
void mySignal(QPrivateSignal);
QPrivateSignal is a private struct created in each QObject subclass by the Q_OBJECT macro, so you can only create QPrivateSignal objects in the current class.
Technically, the signal still has public visibility, but it can only be emitted by the class that created it.
Nowadays you can use Q_SIGNAL macro and normal C++ access specifier:
protected:
Q_SIGNAL void myProtectedSignal();
private:
Q_SIGNAL void myPrivateSignal();
You can use the PIMPL pattern for that. Your private signals exists in the private implementation only.
Related
The documentation states that:
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.
But exactly what does that mean? On which QObject-derived classes can I safely omit it? Will problems arise if you omit Q_OBJECT on a QObject-derived class, and then inherit from that one? Basically I would like a little more information on when I can omit it from my Qt classes.
You should use the Q_OBJECT macro for any non-templated classes that derive from QObject.
Besides signals and slots, the Q_OBJECT macro provides the meta object information that is associated with given class.
As stated in the documentation:
we strongly recommend that all subclasses of QObject use the Q_OBJECT macro regardless of whether or not they actually use signals, slots, and properties.
Suppose we have the following class:
class Class : public QObject {
public:
Class() {}
};
Without Q_OBJECT, the following metaobject system features (among others) will not work for Class:
qobject_cast<Class>() - due to missing metadata
QObject::tr() - due to missing metadata
slots and invokables first declared in Class, when invoked or looked up by name - none of QMetaObject methods will work for these methods, neither will the Qt 4 connect - due to missing metadata
signals - since moc won't generate their implementations and the code won't compile.
You can omit it, of course, but if you ever use these features, you'll need to remember to put the macro into the class's declaration. This is a rather brittle practice and best avoided. The savings are not worth it. So, don't wait - add the Q_OBJECT macro to every class that derives from QObject as a matter of coding policy.
The Q_OBJECT macro should never be used on classes that don't derive from QObject. To add invokables and properties to such classes, use the Q_GADGET macro instead.
If you want to use signals/slots you MUST include the Q_OBJECT macro and derive the class from QObject.
Otherwise you can leave it out, but it doesn't do any harm to include it in all the Qt gui classes
Well the first part is pretty clear as you probably already know.. signals and slots, the rest of the Meta-object system is a little lesser known. Perhaps one of the more useful features is dynamic properties. Although these have many uses, I used them to take advantage of Qt's animation system QPropertyAnimation.
There's a little more info about the meta-object system here: http://doc.qt.io/archives/4.6/metaobjects.html
I think the bottom line is, if you inherit from the QObject hierarchy, throw in the Q_OBJECT macro regardless. It's simple to do and will save you from some potentially baffling problems down the road.
What #liaK said is correct (in short: you should always use the Q_OBJECT macro in any class that derives from QObject).
One thing that I haven't seen highlighted is that if you don't explicitly put the Q_OBJECT macro then using the sometimes very handy qobject_cast won't work!!!
I just realized that I can call pretty much any function of an object that is exposed to QML. Now I am curious about Q_INVOKABLE. The Qt5 docs state:
[...] any QML code can access the following members of an
instance of a QObject-derived class:
Properties
Methods (providing they are public slots or flagged with
Q_INVOKABLE)
Signals
Since Qt5 (In C++) I can invoke any public function of a QObject like a slot, i.e. I do not have to declare them as 'public slot'. Does this mean I can call any method from QML? I cant find anything in the docs.
Yes, you have to mark your function of a QObject with Q_INVOKABLE unless it's a public slot in order to be able to call it from QML.
Both Q_INVOKABLE and the slots keyword register your function with Qt meta-system. The difference is that with Q_INVOKABLE you can return values.
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.
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.
I'm programming in Qt Creator and encountered a problem. I made a singleton class, and I'm trying to connect it to a slot in the widget, but it doesn't take the pointer that returns
from Singleton::getInstance() as the same instance that emits the signal.
My code is as follows:
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void setString(int var);
}
Implementation:
connect(Singleton::getInstance(),SIGNAL(changeString(int)),this,SLOT(setString(int)));
Signal in the singleton class:
signals:
void changeString(int var);
the call to the signal in the singleton class:
emit(Singleton::getInstance()->changeString(5));
Nothing happens when signal emits. The debugger doesn't enter the slot.
Most probably it's the differing method signature of the slot - setString(IMSS_Status); vs. setString(int);
Also, in case of a custom type, you should call
qRegisterMetaType<IMSS_Status>("IMSS_Status");
to register it correctly with the meta type system. Otherwise, queued slot executions won't work, for instance.
Your problem may be caused by signature of the methods. Before you make connect signal with slot u should define your signal to system by using qRegisterMetaType<Your Class >("Class Definition name");
And is the signal of changeString signature ? "void changeString(int)"
i had encountered your problem and i solved my problem by making qRegisterMetaType and controlling signatures.
Does the Singleton class have the Q_OBJECT macro also? I don't know if it needs it also or not.
I would lean towards emit(Singleton::getInstance()->changeString(5)); not being correct.
emit should be called from inside a Singleton function as follows:
emit(changeString(5));
I'm surprised the code you posted compiles and runs without warning, I would have expected a runtime error about the signal not existing.