How to communicate to QWidget's slots through standard C++ class? - c++

I have a standard c++ class, and I want one of its functions to communicate with a Qt widget's slot.
Lets say I have a function foo() in my C++ class, and I want that when ever this function gets called it signal to QWidget for corresponding slot. Since QWidget is used for display purposes
and the standard C++ class is doing something else and I want to changes visual based upon some conditions( i.e. when foo() gets called).
Is it feasible that I can make a C++ class function to trigger a slot of QWidget class?

Related

Where do the arguments passed to slots come from? [duplicate]

Is there a way to use any C++ function as a Qt slot, without having its class inheriting from QWidget?
You cannot in Qt versions < Qt 5.
In order to use signals/slots the meta object compiler has to be invoked. To make this happen your class should meet the following requirements:
Inherit from QObject or any other subclass (eg QWidget, QPushButton etc)
The Q_OBJECT macro should be defined in the private section of the class in order to enable meta-object features such as slots
Use the Qt keywords slots and signals in order to declare which functions should be handles by the meta compiler as slots or signals
For more details check the corresponding documentation pages about the meta-object system and the signals & slots
Also check the QObject documentation:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the
Meta Object Compiler on the source file. We strongly recommend the use
of this macro in all subclasses of QObject regardless of whether or
not they actually use signals, slots and properties, since failure to
do so may lead certain functions to exhibit strange behavior.
Edit: Since Qt 5, functors and lambda expressions can be used as slot. See New Signal Slot Syntax in Qt 5
Since Qt 5, functors and lambda expressions can be used as slot (as previously mentioned, here: http://qt-project.org/wiki/New_Signal_Slot_Syntax).
As I could not find example code, I added the following:
This example uses boost::function for a class member ClassName::classMember() without parameters.
boost::function<void()> f= boost::bind(&ClassName::classMember, classInstance);
connect(QObjectInstance, &QObject::signalName, f);
When the Qt signal and class member have parameters (for instance ClassName::classMember(int)), the boost function should be adapted as follows:
boost::function<void(int)> f= boost::bind(&ClassName::classMember, classInstance, _1);
More information on boost::bind can be found in the documentation: http://www.boost.org/doc/libs/1_55_0/libs/bind/bind.html
In Qt 5, you can. See http://qt-project.org/wiki/New_Signal_Slot_Syntax
In Qt 4, this is not directly supported but there are a couple of libraries which provide this functionality by proxying the signal via a slot in a hidden QObject which then calls your non-slot function. My attempt at this can be found at https://github.com/robertknight/qt-signal-tools . There are links to other implementations on the bottom of the README.
Unlikely. The Qt-meta-object-compiler (moc) wraps the function, are marked as slot-s, in relatively large code-wrapper. Files, created by moc, begin with moc_, look them.
It is enough to inherit QObject: http://qt-project.org/doc/qt-4.8/signalsandslots.html

Is Q_INVOKABLE needed to invoke a public QObject function from QML at all in Qt5?

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.

Connecting to a base class' signal when overriding it in a subclass

Qt provides the QSpinBox, which is some far QObject derivative that provides a signal:
class QSpinBox:
public /* ... */ QObject {
signals:
void valueChanged(int i);
};
When deriving from this spin box, I might provide an override for this signal to emit some beautified version of the value:
class MySpinBox:
public QSpinBox {
private slots:
void originalValueChanged(int i) {
/* Beautify */
emit valueChanged( 42 * i );
}
signals:
void valueChanged(int myPersonalI);
};
This seems perfectly fine: The signal MySpinBox::valueChanged(int) hides the inherited signal. The only bit missing is to connect the inherited QSpinBox::valueChanged(int) to the private slot MySpinBox::originalValueChanged(int).
While this is possible using the new signals and slot syntax:
connect(
static_cast<QSpinBox *>(this), &QSpinBox::valueChanged,
this, &MySpinBox::originalValueChanged);
I am neither sure if this is allowed or sensible, nor how to connect the signal using the conventional string based signal/slot syntax. Using the latter, the slot is obviously connected to the MySpinBox::originalValueChanged(int) signal, which is clearly not intended.
Purpose
The above example is reduced to the problem I think I face. To understand why I ran into the problem and maybe to guide me out of this (pretended) broken design, think of a QDoubleSpinBox derivative to enter some physical quantitiy, e.g. speed. The user may want to enter this in some preferred unit, which may be km/h or mph. To get the unit conversion logic out of the application, I composed a new widget, derived from QWidget and containing only a QDoubleSpinBox. Then I implemented the usual spin box methods (setMinimum, setSingleStep etc.) that take the respective properties in SI dimension (i.e., m/s in this example), convert them to some chosen unit and then configure the inferior double spin box.
A setValue(double) converts its argument to the user's unit and passes it on to the inferior. In turn, there is a valueChanged(double) signal that is emitted whenever the inferior spin box emits valueChanged, but with the quantity converted back to the SI dimension.
So in the end I was tinkering about not composing a QWidget derivative with an inferior spin box but to derive from the QDoubleSpinBox and reimplement.
Pros and cons appear partly clear, including the issue explained by #Pavel Strakhov below already. Composing the widget in fact gets me rid of wrongly inherited methods being called (due to not being virtual), at the cost of a wrapping QWidget. So as an intermediate step, I'm tinkering of deriving private from QDoubleSpinBox. This is surely not a matter of resources in a GUI application, but to me it's also a matter of learning and tinkering.
Then I stumbled about the signal and wondered what Qt might think about it.
Note that QSpinBox::valueChanged is not virtual, meaning that if one have an instance of MySpinBox stored in QSpinBox* pointer and calls its valueChanged method, QSpinBox::valueChanged will be executed instead of MySpinBox::valueChanged. And Qt internal functions will definitely have QSpinBox* pointer to the instance. This inconsistency can be a source of errors. Non-virtual functions are not meant to be redefined in subclasses, and you should not do that. Neither of Qt built-in classes uses such redefinition. Subclasses usually add new signals leaving base class signals untouched.

Pass qml function to c++ class to connect

I have a C++ class that is exposed to QML. The C++ class contains a function that is prefixed with Q_INVOKABLE so it can be called from QML context. Currently, the function expects a QObject and const char * that represents a slot. The function then connects up that slot to an internal C++ signal. Problem is, I don't see any way for QML to trigger this function from it's side because QML functions don't translate to the slot data qt expects. Is there a way to formulate what I am expecting between QML and C++?

Using any c++ function as a Qt slot

Is there a way to use any C++ function as a Qt slot, without having its class inheriting from QWidget?
You cannot in Qt versions < Qt 5.
In order to use signals/slots the meta object compiler has to be invoked. To make this happen your class should meet the following requirements:
Inherit from QObject or any other subclass (eg QWidget, QPushButton etc)
The Q_OBJECT macro should be defined in the private section of the class in order to enable meta-object features such as slots
Use the Qt keywords slots and signals in order to declare which functions should be handles by the meta compiler as slots or signals
For more details check the corresponding documentation pages about the meta-object system and the signals & slots
Also check the QObject documentation:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the
Meta Object Compiler on the source file. We strongly recommend the use
of this macro in all subclasses of QObject regardless of whether or
not they actually use signals, slots and properties, since failure to
do so may lead certain functions to exhibit strange behavior.
Edit: Since Qt 5, functors and lambda expressions can be used as slot. See New Signal Slot Syntax in Qt 5
Since Qt 5, functors and lambda expressions can be used as slot (as previously mentioned, here: http://qt-project.org/wiki/New_Signal_Slot_Syntax).
As I could not find example code, I added the following:
This example uses boost::function for a class member ClassName::classMember() without parameters.
boost::function<void()> f= boost::bind(&ClassName::classMember, classInstance);
connect(QObjectInstance, &QObject::signalName, f);
When the Qt signal and class member have parameters (for instance ClassName::classMember(int)), the boost function should be adapted as follows:
boost::function<void(int)> f= boost::bind(&ClassName::classMember, classInstance, _1);
More information on boost::bind can be found in the documentation: http://www.boost.org/doc/libs/1_55_0/libs/bind/bind.html
In Qt 5, you can. See http://qt-project.org/wiki/New_Signal_Slot_Syntax
In Qt 4, this is not directly supported but there are a couple of libraries which provide this functionality by proxying the signal via a slot in a hidden QObject which then calls your non-slot function. My attempt at this can be found at https://github.com/robertknight/qt-signal-tools . There are links to other implementations on the bottom of the README.
Unlikely. The Qt-meta-object-compiler (moc) wraps the function, are marked as slot-s, in relatively large code-wrapper. Files, created by moc, begin with moc_, look them.
It is enough to inherit QObject: http://qt-project.org/doc/qt-4.8/signalsandslots.html