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
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
So let's suppose I've got a regular Qt class MyQtClass and a class MyClass with ONLY static members. If I want to access the ui of MyQtClass I have to use Signals and Slots. So I create a static Signal (static so I can just invoke it like MyClass::mySignal();) and a slot in the Qt class. How can I connect the static signal from MyClass with the slot from the Qt class, without having an object of MyClass, since it has only got static members?
I know that classes with only static members isn't considered as a good design in c++ but I'm too far into the project by now and I want to know if there's a way to do it with only static members.
Thanks in Advance!
Code:
MyQtClass.h:
#include "ui_MyQtClass.h"
class MyQtClass : public QMainWindow
{
Q_OBJECT
public:
MyQtClass(QWidget *parent = Q_NULLPTR);
Q_SLOT void mySlot();
private:
Ui::MyQtClassClass ui;
};
MyClass.h:
#pragma once
#include <QtWidgets/QMainWindow>
class MyClass : public QObject
{
public:
static void myFunction1();
static void myFunction2();
/*--- More Stuff ---*/
Q_SIGNAL static void mySignal();
};
As indicated in this thread it is not possible to emit static signals since it is always associated with a QObject, as an alternative they create a singleton that would be equivalent to what you want.
#include <QtCore>
class Receiver: public QObject
{
Q_OBJECT
public:
using QObject::QObject;
Q_SLOT void mySlot(){
qDebug()<< __PRETTY_FUNCTION__;
QCoreApplication::quit();
}
};
class Sender: public QObject
{
Q_OBJECT
using QObject::QObject;
public:
static Sender& instance(){
static Sender m_instance;
return m_instance;
}
static void myFunction1(){
emit instance().mySignal();
}
Q_SIGNAL void mySignal();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Receiver r;
QObject::connect(&Sender::instance(), &Sender::mySignal, &r, &Receiver::mySlot);
QTimer::singleShot(1000, &Sender::myFunction1);
return a.exec();
}
#include "main.moc"
I've got a c++ code including GUI, in which I need to run a time consuming loop for optimization.
class OptimizationAlgorith(data *data);
{
private:
var var1;
var var2;
public:
method1();
method2();
..
timeConsumingMethod(data);
}
this need to be called in a GUI class like following:
class QRegistration: public QWidget
{
Q_OBJECT
private:
data *m_data;
QPushButton *m_button_run;
OptimizationAlgorithm *m_optimizationalgorithm;
WorkerThread *m_workerThread;
QThread *m_thread;
..
private slots:
void on_pushButton_run_clicked();
void registrationDone();
I need to move the timeConsumingMethod into a seperate thread than main thread, so that the GUI does not freez while timeConsumingMethodis running.
I have made a new class "WorkerThread" using the official documentation of Qt, which looks like:
class WorkerThread : public QObject
{
Q_OBJECT
public:
WorkerThread(ApplicationData* data, QOptimizationAlgorithm * OptimizationAlgorithm);
~WorkerThread();
public slots:
void run(data* data);
signals:
void finished();
private slots:
private:
OptimizationAlgorithm *m_OptimizationAlgorithm;
ApplicationData *m_data;
}
How shoud I now implement my run()in WorkerThread? Can I simply write:
void WorkerThread::run(data *m_data)
{
m_optimization.timeConsumingMethod(m_data);
emit finished();
}
or do I have to copy the whole definition of timeConsumingMethod in run()? Why/Why not?
You don't need to do any explicit thread management, Qt already does it for you. Use QtConcurrent::run to do the work in a worker thread from the thread pool.
You should also decouple the controller that manages the work, and the UI. The knowledge of how to couple these objects should be separate from the objects themselves. This allows more flexibility in the design of the UI and the controller, and helps avoid several classes of errors that stem from accessing non-thread-safe methods from incorrect threads.
Complete example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/threadwork-simple-40865259
#include <QtWidgets>
#include <QtConcurrent>
struct ApplicationData {};
struct OptimizationAlgorithm {
void timeConsumingMethod(QSharedPointer<ApplicationData>) {
QThread::sleep(3);
}
};
class Controller : public QObject {
Q_OBJECT
QSharedPointer<ApplicationData> m_data{new ApplicationData};
OptimizationAlgorithm m_algorithm;
public:
Q_SLOT void run() {
QtConcurrent::run([this]{
emit busy();
m_algorithm.timeConsumingMethod(m_data);
emit finished();
});
}
Q_SIGNAL void busy();
Q_SIGNAL void finished();
};
class Registration : public QWidget {
Q_OBJECT
QVBoxLayout m_layout{this};
QLabel m_status{"Idle"};
QPushButton m_run{"Run"};
public:
Registration() {
m_layout.addWidget(&m_status);
m_layout.addWidget(&m_run);
connect(&m_run, &QPushButton::clicked, this, &Registration::reqRun);
}
Q_SIGNAL void reqRun();
Q_SLOT void onBusy() { m_status.setText("Running"); }
Q_SLOT void onFinished() { m_status.setText("Idle"); }
};
void setup(Registration *reg, Controller *ctl) {
using Q = QObject;
Q::connect(reg, &Registration::reqRun, ctl, &Controller::run);
Q::connect(ctl, &Controller::busy, reg, &Registration::onBusy);
Q::connect(ctl, &Controller::finished, reg, &Registration::onFinished);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Controller ctl;
Registration reg;
setup(®, &ctl);
reg.show();
return app.exec();
}
#include "main.moc"
I wrote a simple program which emits signal inside run function of a QThread inherited class and in another class which inherits QObject wrote a slot to catch the signal, but when I compile the code I get the following errors:
symbols(s) not found for architecture x86_64
collect2: ld returned 1 exit status
and here is my code :
class visionThread : public QThread
{
public:
visionThread();
void run();
signals:
void newVisionPacket();
};
visionThread::visionThread():QThread(){
}
void visionThread::run()
{
for(int i = 0 ; i<10 ; i++)
{
emit newVisionPacket();
usleep(1000);
}
}
class dummyClass: public QObject{
public:
dummyClass(){
}
void doConnect(visionThread* v){
connect(v , SIGNAL(newVisionPacket()) , this , SLOT(mySlot()));
}
public slots:
void mySlot(){
usleep(2000);
qDebug() << "HI" << endl;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
visionThread *vision;
vision = new visionThread();
dummyClass *dummyObject = new dummyClass();
dummyObject->doConnect(vision);
vision->start(QThread::NormalPriority);
return a.exec();
}
I'm so confused, and I would deeply appreciate any solutions.
You have not placed Q_OBJECT macro in your classes.They should be like:
class visionThread : public QThread
{
Q_OBJECT
public:
visionThread();
void run();
signals:
void newVisionPacket();
};
And
class dummyClass: public QObject{
Q_OBJECT
public:
dummyClass(){
}
void doConnect(visionThread* v){
connect(v , SIGNAL(newVisionPacket()) , this , SLOT(mySlot()));
}
public slots:
void mySlot(){
usleep(2000);
qDebug() << "HI" << endl;
}
};
After adding the Q_OBJECT macro Clean the project, run qmake and rebuild it.
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.