How would I connect this signal to the slot - c++

I would like to create a signal in my main class foo so that a static method in a different class could emit it.I just started of with QT so I am a bit confused. I currently have the following code
class Foo : public QMainWindow
{
Q_OBJECT
public:
Foo(QWidget *parent = 0, Qt::WFlags flags = 0);
~Foo();
signals:
void UpdateSignal(int val);
private slots:
void MySlot(int val);
};
Foo::Foo(QWidget *parent, Qt::WFlags flags): QMainWindow(parent, flags)
{
//How do I connect Bfoo::somemethod() here. I know its suppose to be like
connect(xx,SIGNAL(UpdateSignal(int)),this, SLOT(MySlot(int)));
ui.setupUi(this);
}
void Foo::MySlot(int val)
{
//Do something..
}
Now I have this class
Class Bfoo
{
static void somemethod()
{
emit UpdateSignal(12);
}
}
Any suggestions on how the static somemethod() could emit the UpdateSignal

When you emit signal it is necessary to know which object is emitting it. This is because signals are not implemented to be messages between different classes but messages between instances of (possibly different) classes.
Secondly, signals are protected methods. They are not accessible for external users. What you can do is define public method in Foo which will do the emission:
void Foo:EmitUpdateSignal(int x) {
emit UpdateSignal(x);
}
And then in your Bfoo::somemethod() you need to pass object which will emit signal:
void BFoo::somemethod(Foo &f) {
f.EmitUpdateSignal(12);
}
However, notice what you are doing. You emit signal which is connected to the slot in the same instance. This suggests design flaw but I cannot give any hints without more details about what are you going to achieve.

Related

Qt Slot and signal are not connected: No such signal

I am trying to deal with slots and signals in Qt, for this I am trying to do the following:
The MyTestClass class should send a signal to the ReceiverClass class, the code:
mytestclass.h
class MyTestClass : public QObject
{
Q_OBJECT
public:
MyTestClass();
void makeSignal();
signals:
void sendSignal();
};
mytestclass.cpp
MyTestClass::MyTestClass()
{
}
void MyTestClass::makeSignal()
{
emit sendSignal();
}
reseiverclass.h
class ReceiverClass : public QObject
{
Q_OBJECT
public:
ReceiverClass();
public slots:
void receiverSlot();
};
reseiverclass.cpp
ReceiverClass::ReceiverClass()
{
}
void ReceiverClass::receiverSlot()
{
qInfo() << "receiverSlot called!\n";
}
main.cpp
...
MyTestClass testObj;
ReceiverClass receiverObj;
QObject::connect(&testObj, SIGNAL(&testObj::sendSignal()), &receiverObj, SLOT(&receiverObj::receiverSlot));
testObj.makeSignal();
...
However, I encounter such an error.
Why doesn't Qt see the signal?
QObject::connect: No such signal MyTestClass::&testObj::sendSignal() in ..\testQtProject\main.cpp:15
QObject::connect(&testObj, SIGNAL(&testObj::sendSignal()), &receiverObj, SLOT(&receiverObj::receiverSlot));
You are mixing the syntax of the 2 methods for connecting signal and slots in Qt, either use :
QObject::connect(&testObj, SIGNAL(sendSignal()), &receiverObj, SLOT(receiverSlot()));
or
QObject::connect(&testObj, &testObj::sendSignal, &receiverObj, &receiverObj::receiverSlot);
For more informations, look at https://doc.qt.io/qt-5/signalsandslots.html and https://wiki.qt.io/New_Signal_Slot_Syntax

Q_PROPERTY System not working as expected

I have this class I intended to use in the context of a qml engine so in order to use property binding I setted up these Q_PROPERY macros. I want to use the MEMBER keyword and have the notify signal emitted automatically.
class InterfaceBackend : public QObject
{
Q_OBJECT
Q_PROPERTY(quint8 current_view MEMBER m_current_view NOTIFY sCurrentViewChanged)
Q_PROPERTY(quint8 future_view MEMBER m_future_view NOTIFY sFutureViewChanged)
public:
explicit InterfaceBackend(QObject *parent = 0);
~InterfaceBackend();
quint8 getCurrentView() { return this->m_current_view; }
quint8 getFutureView() { return this->m_future_view; }
private:
quint8 m_current_view;
quint8 m_future_view;
QByteArray m_selected_language;
public slots:
void onLanguageSelected(QByteArray language);
private slots:
signals:
void sCurrentViewChanged(quint8 current_view);
void sFutureViewChanged(quint8 future_view);
};
InterfaceBackend::InterfaceBackend(QObject *parent) : QObject(parent)
{
this->setObjectName("backend");
QObject::connect(this, &InterfaceBackend::sFutureViewChanged, []() {qDebug() << "sFutureViewChanged";});
this->m_current_view=1;
this->m_future_view=1;
}
InterfaceBackend::~InterfaceBackend()
{
}
void InterfaceBackend::onLanguageSelected(QByteArray language)
{
this->m_selected_language=language;
this->m_future_view=2;
}
qt docs say:
A NOTIFY signal is optional. If defined, it should specify one existing signal in that class that is emitted whenever the value of the property changes. NOTIFY signals for MEMBER variables must take zero or one parameter, which must be of the same type as the property. The parameter will take the new value of the property. The NOTIFY signal should only be emitted when the property has really been changed, to avoid bindings being unnecessarily re-evaluated in QML, for example. Qt emits automatically that signal when needed for MEMBER properties that do not have an explicit setter
But whenever I call the slot the signals never gets called nor the property is updated in the qml model, what's wrong!?
To give an answer that is technically more accurate:
The MEMBER in Q_PROPERTY will tell the moc (Meta object compiler) that when accessing the property via the meta object it should use the member directly instead of a getter or setter method. So the moc will the generate a setter method internally that sets the member and emits the signal - it basically just does the work of writing getters/setters for you. Since changing a member needs to emit the change signal, this is automatically done when the property is written from the meta object system. So, calling:
backend->setProperty("future_view", future_view);
will correctly emit the changed signal. This is the only guarantee that is given when using MEMBER. Changes, that are done via the meta property will trigger the change signal. This means if you would set future_view from QML directly, without the onLanguageSelected method, it would actually work.
In your example however you directly write a value to the member inside a special method - This will not trigger the signal automatically! (I mean, how should Qt even know you did that). So what you need to do is whenever you change the value of your member you need to emit the change signal yourself:
void onLanguageSelected(QByteArray language)
{
this->m_selected_language=language;
this->m_future_view=2;
emit sFutureViewChanged();
}
Edit: If you were trying prevent the properties from beeing written directly from QML, using MEMBER will not work! Use a getter instead and only register the getter with the property. Use the same code as above to write and change the properties:
Q_PROPERTY(quint8 future_view READ futureView NOTIFY sFutureViewChanged)
As you can see in this article:
New keyword in Q_PROPERTY: MEMBER let you bind a property to a class member without requiring to have a getter or a setter.
So you should remove your getters, and your result code will look like this
class InterfaceBackend : public QObject
{
Q_OBJECT
Q_PROPERTY(quint8 current_view MEMBER m_current_view NOTIFY sCurrentViewChanged)
Q_PROPERTY(quint8 future_view MEMBER m_future_view NOTIFY sFutureViewChanged)
public:
explicit InterfaceBackend(QObject *parent = 0)
: QObject(parent)
{
this->setObjectName("backend");
QObject::connect(this, &InterfaceBackend::sFutureViewChanged, []() { qDebug() << "sFutureViewChanged";});
this->m_current_view=1;
emit sCurrentViewChanged();
this->m_future_view=1;
emit sFutureViewChanged();
}
~InterfaceBackend() = default;
private:
quint8 m_current_view;
quint8 m_future_view;
QByteArray m_selected_language;
public slots:
void onLanguageSelected(QByteArray language) {
this->m_selected_language=language;
this->m_future_view=2;
emit sFutureViewChanged();
}
signals:
void sCurrentViewChanged();
void sFutureViewChanged();
};
Every Q_PROPERTY must have READ public method and WRITE public slot, also the signal will never automatically emited, you should emit it whenever MEMBER change.
class InterfaceBackend : public QObject
{
Q_OBJECT
Q_PROPERTY(quint8 current_view MEMBER m_current_view READ currentView WRITE setCurrentView NOTIFY sCurrentViewChanged)
Q_PROPERTY(quint8 future_view MEMBER m_future_view READ futureView WRITE setFutureView NOTIFY sFutureViewChanged)
public:
explicit InterfaceBackend(QObject *parent = 0);
~InterfaceBackend();
quint8 currentView() const
{
return m_current_view;
}
quint8 futureView() const
{
return m_future_view;
}
private:
quint8 m_current_view;
quint8 m_future_view;
QByteArray m_selected_language;
public slots:
void onLanguageSelected(QByteArray language);
void setCurrentView(quint8 current_view)
{
if (m_current_view == current_view)
return;
m_current_view = current_view;
emit sCurrentViewChanged(m_current_view);
}
void setFutureView(quint8 future_view)
{
if (m_future_view == future_view)
return;
m_future_view = future_view;
emit sFutureViewChanged(m_future_view);
}
private slots:
signals:
void sCurrentViewChanged(quint8 current_view);
void sFutureViewChanged(quint8 future_view);
};
InterfaceBackend::InterfaceBackend(QObject *parent) : QObject(parent)
{
this->setObjectName("backend");
QObject::connect(this, &InterfaceBackend::sFutureViewChanged, []() {qDebug() << "sFutureViewChanged";});
this->m_current_view=1;
this->m_future_view=1;
}
InterfaceBackend::~InterfaceBackend()
{
}
void InterfaceBackend::onLanguageSelected(QByteArray language)
{
this->m_selected_language=language;
this->m_future_view=2;
}
Spending some time, I got it working as I need, althought this is EXTREMELY UGLY and BY NO MEANS DECLARATIVE I think it is the only way to achive double binding, and maybe it will be helpful for other people approaching the problem. Note this is not an accepted answer, I still hope someone somewhere, perhaps in the future if and when Qt will be updated, could come up with a far more elegant solution.
Main disadvantages: longer and verbose code, one has to use setters everywhere and (try not forget)
The property system doesn't do anything automatically in the end, just states wich properties are exposed and wich are their getters/setters and change signals
c++
class InterfaceController : public QObject
{
Q_OBJECT
Q_PROPERTY(quint8 current_view READ getCurrentView WRITE setCurrentView NOTIFY sCurrentViewChanged)
Q_PROPERTY(quint8 future_view READ getFutureView WRITE setFutureView NOTIFY sFutureViewChanged)
public:
explicit InterfaceController(QObject *parent = 0);
//getters
quint8 getCurrentView() { return this->m_current_view; }
quint8 getFutureView() { return this->m_future_view; }
//setters
Q_INVOKABLE void setCurrentView(quint8 current_view) { if(this->m_current_view!=current_view) {this->m_current_view=current_view; emit sCurrentViewChanged(this->m_current_view);} }
Q_INVOKABLE void setFutureView(quint8 future_view) { if(this->m_future_view!=future_view) {this->m_future_view=future_view; emit sFutureViewChanged(this->m_future_view);} }
private:
quint8 m_current_view;
quint8 m_future_view;
QByteArray m_selected_language;
public slots:
void onLanguageSelected(QByteArray language);
private slots:
signals:
void sCurrentViewChanged(quint8 current_view);
void sFutureViewChanged(quint8 future_view);
};
InterfaceController::InterfaceController(QObject *parent) : QObject(parent)
{
this->m_current_view=1;
this->m_future_view=1;
}
void InterfaceController::onLanguageSelected(QByteArray language)
{
this->m_selected_language=language;
this->setFutureView(2);
}
QML
id: root
property int current_view: 1
property int future_view: 1
Connections {
target: root
onCurrent_viewChanged: { backend.setCurrentView(current_view); }
onFuture_viewChanged: { backend.setFutureView(future_view); }
}
Connections {
target: backend
onSCurrentViewChanged: { if(root.current_view!=current_view) {root.current_view=current_view;} }
onSFutureViewChanged: { if(root.future_view!=future_view) {root.future_view=future_view;} }
}

Qt connect doesn't works

I've a C++ library. This library uses the publish-subscriber pattern.
namespace mylib {
typedef unsigned MyLibType;
class IEvent
{
virutal ~IEvent() {}
virtual void event1() = 0;
virtual void event2(MyLibType) = 0;
};
class IMyClass
{
public:
virtual ~IMyClass() {}
// operations
};
} // mylib
// C interface
int CreateMyClass( mylib::IMyClass** class, mylib::IEvent* listener );
// implementation
class MyClass : public IMyClass { // ...
When MyClass is create uses a thread that generate some events.
Now on Qt:
class QtMyApplication : public QMainWindow, public mylib::IEvent
{
Q_OBJECT
public:
explicit QtMyApplication(QWidget *parent = 0);
~QtMyApplication();
signals:
void MyLibEvent1();
void MyLibEvent2(mylib::MyLibType);
private slots:
void OnMyLibEvent1();
void OnMyLibEvent2(mylib::MyLibType);
private: // IEvent interface
void event1()
{
emit MyLibEvent1();
}
void event2(mylib::MyLibType i)
{
emit OnMyLibEvent2( i );
}
private:
Ui::QtMyApplication* ui;
mylib::IMyLib mMyLib;
};
// implementation
QtMyApplication::QtMyApplication( QWidget *parent ) :
QMainWindow(parent),
ui(new Ui::QtMyApplication)
{
ui->setupUi( this );
CreateMyLib( &mMyLib, this );
connect( this, SIGNAL(MyLibEvent1()),
this, SLOT(OnMyLibEvent1()) );
connect( this, SIGNAL(MyLibEvent2(mylib::MyLibType)),
this, SLOT(OnMyLibEvent2(mylib::MyLibType)) );
}
When I run the application event2() is called inside QtMyApplication but OnMyLibEvent2 is never called, instead event1() is called and OnMyLibEvent1 is called too.
What am I wrong? Is the argument parameter the issue?
edit 1
I discovered that the connect has some restriction on params.... because if I change MyLibEvent2(mylib::MyLibType) in MyLibEvent2(int) all works properly...
You need to register your datatype to QTs metatype system to make it work:
qRegisterMetaType<mylib::MyLibType>();
QTs metatype system does not know about typedefs, and therefore does not know how to transfer a mylib::MyLibType.
I'm not exactly shure if you need Q_DECLARE_METATYPE(mylib::MyLibType) too, try it if you have no success.
If you use QT5s new connection syntax then it might also work without any additonal effort.
connect( this, &QtMyApplication::MyLibEvent2,
this, &QtMyApplication::OnMyLibEvent2);
The problem is that the old connect syntax is working around the metadata system and string comparisons and is fairly fragile. It also won't work if you decide to update your slot to void OnMyLibEvent2(::mylib::MyLibType)

Qt fire different signal depending on parameter type

I need to fire different signal from SomeClass::fireSignal member function depending on it parameters type. The solution I see is to use Qt meta system. Is there more correct solution for such task? Please help. Thanks in advance.
class SomeClass : public QObject
{
Q_OBJECT
public:
void fireSignal(BaseClass *param) {
if(param->metaObject->className() == "DerivedClass1") {
emit derivedClass1Signal(param)
}
if(param->metaObject->className() == "SecondDerivedClass") {
emit secondDerivedClassSignal(param)
}
if(param->metaObject->className() == "OtherDerivedClass") {
emit otherDerivedClassSignal(param)
}
}
signals:
void derivedClass1Signal(DerivedClass1 *param);
void secondDerivedClassSignal(SecondDerivedClass *param);
void otherDerivedClassSignal(OtherDerivedClass *param)
};
Maybe try:
class SomeClass : public QObject
{
Q_OBJECT
public:
void fireSignal(BaseClass *param) {
if(param->metaObject->className() == DerivedCass::staticMetaObject.className()) {
emit sig(qobject_cast<DerivedClass*>(param);
}
if(param->metaObject->className() == SecondDerivedClass::staticMetaObject.className()) {
emit sig(qobject_cast<SecondDerivedClass*>(param);
}
if(param->metaObject->className() == OtherDerivedClass::staticMetaObject.className()) {
emit sig(qobject_cast<OtherDerivedClass*>(param);
}
}
signals:
void sig(DerivedClass1 *param);
void sig(SecondDerivedClass *param);
void sig(OtherDerivedClass *param)
};
Generally speaking, this is Ok. You can make some improvements, but that will heavilly depend on how you are using these signals. For example, if all three are connected to the same slot(s), you can reduce your code here, leaving one signal that has one argument which is a pointer of a base class:
class SomeClass : public QObject
{
Q_OBJECT
public:
void fireSignal(BaseClass *param) {
emit derivedClassSignal(param);
}
signals:
void derivedClassSignal(DerivedClass1 *param);
};
However, removing the check from the sender's code will force you to include it into the receiver's code (i.e. the check for which exact derived type was passed). If, however, each signal is connected to a different slot, and those slots require only a specific type of argument, this will not work, and your approach will be better.

"Reparent" classes from compiled code

Following case:
Let's say there is a binary library which defines the class "Base", and many subclasses ("Derivative1", "Derivative2" etc) of it.
I want to extend these subclasses in my own code, but because my extensions are the same for all subclasses as they only deal with parts of Base, it would be tedious to subclass every Derivative class and add the same code over and over again.
My first idea was to simply write a class template which would do the work for me, but because the library I'm dealing with is Qt, QObject has foiled me.
My second idea was to use macros to generate each class structure, but this was also thwarted by moc.
The "reparent" in the title is because I thought of deriving from Base and creating BaseExtended, and then somehow tell the compiler to reparent every Derivative to this extended class. Isn't there a way to for example declare the "Base" in "BaseExtended" virtual, and then just write
class Derivative1Extended : public Derivative1, public BaseExtended {}
and have the virtual Base in BaseExtended point to the Base in Derivative1, thus basically "squeezing ing" my extensions between Base and Derivative1?
(By the way, I tried to keep the above as generic as possible, but what I'm actually doing is trying add signals for "focusIn" and "focusOut" to every QWidget derivative without writing the same code over and over again for every QWidget subclass I use)
EDIT:
For reference, here's my current implementation:
// qwidgetfs.h
class QLineEditFS : public QLineEdit
{
Q_OBJECT
private:
void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *);
public:
QLineEditFS(QWidget *parent = 0);
signals:
void focusReceived(QWidgetFS::InputType);
void focusLost();
};
// qwidgetfs.cpp
QLineEditFS::QLineEditFS(QWidget *parent /*= 0*/)
: QLineEdit(parent)
{}
void QLineEditFS::focusInEvent(QFocusEvent *e)
{
QLineEdit::focusInEvent(e);
emit focusReceived(QWidgetFS::InputText);
}
void QLineEditFS::focusOutEvent(QFocusEvent *e)
{
QLineEdit::focusOutEvent(e);
emit focusLost();
}
And this repeated for QSpinBoxFS, QComboBoxFS, QCheckBoxFS and so on...
Instead I would like to just define this logic in a common class QWidgetFS, and then "inject" it into other classes derived from QWidget
I'm not sure you'll really be able to do what you are suggesting without modifying Qt and recompiling it.
Perhaps to do what you want, you could use event filters installed on the objects that you want to handle focus events from?
little test app:
header:
class FocusEventFilter : public QObject
{
Q_OBJECT
public:
FocusEventFilter(QObject* parent)
: QObject(parent)
{}
Q_SIGNALS:
void focusIn(QWidget* obj, QFocusEvent* e);
void focusOut(QWidget* obj, QFocusEvent* e);
protected:
bool eventFilter(QObject *obj, QEvent *e);
};
class testfocus : public QMainWindow
{
Q_OBJECT
public:
testfocus(QWidget *parent = 0, Qt::WFlags flags = 0);
~testfocus();
public Q_SLOTS:
void onFocusIn(QWidget*, QFocusEvent*);
void onFocusOut(QWidget*, QFocusEvent*);
private:
Ui::testfocusClass ui;
};
Implementation
#include <QFocusEvent>
#include "testfocus.h"
bool FocusEventFilter::eventFilter(QObject *obj, QEvent *e)
{
if (e->type() == QEvent::FocusIn) {
bool r = QObject::eventFilter(obj, e);
QFocusEvent *focus = static_cast<QFocusEvent*>(e);
QWidget* w = qobject_cast<QWidget*>(obj);
if (w) {
emit focusIn(w, focus);
}
return r;
}
else if (e->type() == QEvent::FocusOut) {
bool r = QObject::eventFilter(obj, e);
QFocusEvent *focus = static_cast<QFocusEvent*>(e);
QWidget* w = qobject_cast<QWidget*>(obj);
if (w) {
emit focusOut(w, focus);
}
return r;
}
else {
// standard event processing
return QObject::eventFilter(obj, e);
}
}
testfocus::testfocus(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
FocusEventFilter* filter = new FocusEventFilter(this);
ui.lineEdit->installEventFilter(filter);
ui.lineEdit_2->installEventFilter(filter);
connect(filter, SIGNAL(focusIn(QWidget*, QFocusEvent*)), this, SLOT(onFocusIn(QWidget*, QFocusEvent*)));
connect(filter, SIGNAL(focusOut(QWidget*, QFocusEvent*)), this, SLOT(onFocusOut(QWidget*, QFocusEvent*)));
}
testfocus::~testfocus()
{
}
void testfocus::onFocusIn(QWidget* obj, QFocusEvent*)
{
obj->setStyleSheet("background-color:#aaaaff;");
}
void testfocus::onFocusOut(QWidget* obj, QFocusEvent*)
{
obj->setStyleSheet("background-color:#ffaaaa;");
}
Of course, YMMV. You could always have a separate filter per object. This method means you can avoid deriving from everything. Not as efficient but it should work.
You may be able to do what you want in the event filter itself rather than using signals/slots.
I have done stuff like this in the past with templates. The problem is that you can't use signals.
I'm typing this up without a compiler so please be kind :):
template<typename T>
class FSWidget: public T
{
public:
FSWidget()
{
_delegate = NULL;
}
setDelegate(FSDelegate *delegate)
{
_delegate = delegate;
}
protected:
virtual void focusInEvent(QFocusEvent *e)
{
T::focusInEvent(e);
if (_delegate) {
_delegate->focusInEvent(this);
}
}
virtual void focusOutEvent(QFocusEvent *e)
{
T::focusOutEvent(e);
if (_delegate) {
_delegate->focusOutEvent(this);
}
}
private:
FSDelegate *_delegate;
};
So, the advantage is when you need to use this you can basically create a class like this:
FSWidget<QLineEdit *> lineEdit = new FSWidget<QLineEdit *>;
lineEdit->setDelegate(delegate);
You can put in whatever you want instead of QLineEdit and it will work.
And then teh FSDelegate could be just an interface that you mix into whatever class needs to act on the info. It could be one of these:
class FSDelegate
{
public:
virtual void focusInEvent(QWidget *w) = 0;
virtual void focusOutEvent(QWidget *w) = 0;
};
If you're always doing the same thing in on focusInEvent and focusOutEvents, you can implement these functions and make a real Mixin class.
Hopefully this can avoid some code duplication for you.