I have a problem with the QServiceManager.
QServiceManager manager;
CFoo bar;
QList<QServiceInterfaceDescriptor> ServiceList = manager.findInterfaces(SERVICE_NAME);
for(int i = 0; i < ServiceList.length(); i++)
{
bool accessGranted = false;
QServiceInterfaceDescriptor descriptor = ServiceList[i];
if (descriptor.interfaceName() == INTERFACE)
{
bar = manager.loadLocalTypedInterface<IFoo>(descriptor, accessGranted);
if (NULL == bar && false == accessGranted)
{
connect(bar, SIGNAL(signal()),
this, SLOT(slot()));
}
}
}
I can do function calls specified in the interface IFoo on bar, like:
bar.function()
and I see that the remote object foo is receiving the function call, but when I send the signal remotely:
class IFoo : public QObject
{
Q_OBJECT
public:
virtual void function() = 0:
signals:
void signal();
};
class CFoo : public IFoo`
{
Q_OBJECT
void function()
{
emit signal();
}
};
it is not received. The function slot() is never called. I checked that the connect function gets called and returns TRUE. Can anybody pinpoint what I am doing wrong?
Cant use signals and slots if your class isnt qobject
#include<QObject>
class CFoo : public QObject, public IFoo
{
Q_OBJECT
signals:
void signal();
public:
void function()
{
emit signal();
}
};
Related
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
This code fails on second Q_ASSERT.
class A : public QObject
{
Q_OBJECT
public:
void function(QObject *receiveOb, const char *slot)
{
Q_ASSERT((bool)connect(this, SIGNAL(mySignal(int)), receiveOb, SLOT(mySlot(int))));
Q_ASSERT(receiveOb->metaObject()->indexOfMethod(slot) != -1);
}
signals:
void mySignal(int param);
};
class MainClass : public QObject
{
Q_OBJECT
A a;
public slots:
void mySlot(int param)
{
param++;
}
public:
MainClass(QObject *papi = Q_NULLPTR) : QObject(papi)
{ }
void doIt()
{
a.function(this, SLOT(mySlot(int)));
}
};
As I can see, if connect is able to lookup the slot method, I could do the same.
What am I doing wrong?
What other checks can I do to find out my mistake?
I have a question - how to connect base class signal to inherited class slot.
I`ve got a code like this
class A: public QObject
{
Q_OBJECT
public:
A(){}
void EmitSignal()
{
emit(Asignal());
}
signals:
void Asignal();
};
class B: public A
{
public:
B();
public slots:
void Bslot()
{
//dosmth
}
};
B::B()
{
connect(this, SIGNAL(Asignal()), this, SLOT(Bslot()));
}
int main(int argc, char *argv[])
{
B Bobject;
B.EmitSignal();
}
and when I call B.EmitSignal() I suppose to have Bslot() called, but I got a message in output window
QObject::connect: No such slot A::Bslot().
How can I achieve Bslot() execution?
Found the solution. I forgot Q_OBJECT macro in inherited class
I've got problem with QTimer in Qt C++, in my code timeoutHandler() is not called. Can anyone tell me why and how I can fix it?
Test.h
class Test : public QObject
{
Q_OBJECT
private:
static bool timeOuted;
public:
explicit Test(QObject *parent = 0);
virtual ~Test();
public slots:
static void handleTimeout();
};
Test.cpp
void Test::run()
{
QTimer::singleShot(3000, this, SLOT(handleTimeout()));
while(!timeOuted);
if(timeOuted)
{
timeOuted = false;
}
else
{
/* some work */
}
}
bool Test::timeOuted = false;
void Test::handleTimeout()
{
static int i = 0;
timeOuted = true;
qDebug() << "TimeOuted " << i++;
}
QTimer requires Qt event loop to work. When you enter the while(!timeOuted);, you block the current thread endlessly and the Qt's event loop has no chance to take any action (like calling your handler for the timer). Here's how you should do it:
Test.h:
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = 0);
virtual ~Test();
void run(); // <-- you missed this
private slots: // <-- no need to make this slot public
void handleTimeout(); // <-- why would you make it static?!
};
Test.cpp:
void Test::run()
{
QTimer::singleShot(3000, this, SLOT(handleTimeout()));
}
void Test::handleTimeout()
{
static int i = 0;
qDebug() << "TimeOuted " << i++;
/* some work */
}
To update answer from Googie you can use also lambda from C++11:
QTimer::singleShot(10000, [=]() {
// Handle timeout here
});
using Qt 5.0.0
The following is roughly an Observer pattern (the code is stripped to bare minimum to explain only the problem):
class A : public QObject
{
Q_OBJECT
public:
void registerListner(Observer *pObs);
static A* getInstance();
signals:
void sig();
};
void A::registerListner(Observer *pObs)
{
connect(this, SIGNAL(sig()), pObs, SLOT(slo));
}
////////////////////////////////////////////////////////////////
class Observer : public QObject
{
Q_OBJECT
public slots:
virtual void slo() = 0;
};
class ConcreteObserver : public Observer , public QWidget
{
Q_OBJECT
public: //re-mentioning "slots" is not necessary
virtual void slo();
};
ConcreteObserver *pCObs = new ConcreteObserver;
A::getInstance()->registerListner(pCObs);
/////////////////////////////////////////////////////////////
problem (apart from dreaded-diamond):
Can't inherit multiple times from QObject - moc does not allow it.
One possible solution is derive Observer from QWidget and then ConcreteObserver from Observer alone. However this is putting a constraint on ConcreteObserver. Maybe ConcreteObserver_2 needs to derive from QDialog instead etc.
How do i solve this design problem? Is there anything specific to Qt 5.0.0 Signal-Slot (in addition to earlier versions) that can solve this, or what would you suggest?
If runtime warnings are not enough for you, you can add a bit of compile-time type checking by making registerListener a function template and avoid multiple inheritance of QObject by not defining an Observer class per-se.
Here's what this could look like: (Note: my SFINAE skills are non-existent, this could probably be made nicer.)
#include <QObject>
#include <QDebug>
#include <type_traits>
class A : public QObject
{
Q_OBJECT
public:
template <typename T>
void registerListener(T *pObs)
{
static_assert(std::is_base_of<QObject, T>::value,
"Listener must be a QObject");
static_assert(std::is_same<void,
decltype(std::declval<T>().slo())
>::value,
"Slot slo must have signature void slo();");
connect(this, SIGNAL(sig()), pObs, SLOT(slo()));
}
static A* getInstance() { return instance; }
static void init() { instance = new A; }
void doStuff() { emit sig(); }
signals:
void sig();
private:
static A *instance;
};
A few test cases:
class BadObject1 : public QObject
{
Q_OBJECT
public:
BadObject1() {}
public slots:
void slo(int){}
};
class BadObject2 : public QObject
{
Q_OBJECT
public:
BadObject2() {}
public slots:
int slo(){return 0;}
};
struct BadObject3 {
void slo();
};
class ObservedObject : public QObject
{
Q_OBJECT
public:
ObservedObject(QString const& name): QObject() {
setObjectName(name);
}
public slots:
virtual void slo(){
qDebug() << objectName();
}
};
class ObservedObject2 : public ObservedObject
{
Q_OBJECT
public:
ObservedObject2(QString const& name)
: ObservedObject(name + " (derived)") {}
};
And a main file:
#include "A.h"
A* A::instance = 0;
int main(int , char **)
{
A::init();
A::getInstance()->registerListener(new BadObject1);
A::getInstance()->registerListener(new BadObject2);
A::getInstance()->registerListener(new BadObject3);
A::getInstance()->registerListener(new ObservedObject("foo"));
A::getInstance()->registerListener(new ObservedObject2("bar"));
A::getInstance()->doStuff();
}
You'll get compiler errors for all the BadObjectN cases. If you comment them out, the output will look like:
"foo"
"bar (derived)"
A warning though: this will not check if the void slo(); member is indeed a slot. You can check that at runtime with something like:
if (pObs->metaObject()->indexOfSlot("slo()") == -1) {
qDebug() << "Class" << pObs->metaObject()->className()
<< "doesn't have a slo slot.";
::exit(1);
}
This will work and do what is expected (unless you've got a class hierarchy where the slot wasn't declared virtual - then strange things will happen in derived classes that omit the slots "specifier". So I advocate that your docs not have the comment you have above about that specifier: it is always a good idea to have it when overloading a slot).
I don't believe this last check is achievable at compile-time, "slot resolution" is done with a runtime walk of the QObject meta-data and involves parsing moc-generated strings. Even if it was with some recursive template magic, I don't think it's work the effort. You'll get a runtime error message at registration type in which you can include the actual class name of the faulty object. That's a very accurate error message, and should be caught by the simplest testcases.