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.
Related
I'm using the MVC pattern and I'm trying to connect a signal from my view class with my controller class that inherits QObject
class View : public QWidget
{
Q_OBJECT
private:
Controller* controller;
QPushButton* startButton;
void addControls(QVBoxLayout* mainLayout);
public:
explicit View(QWidget *parent = nullptr);
void setController(Controller* c);
};
#endif // VIEW_H
This are the methods
void View::addControls(QVBoxLayout *mainLayout)
{
//I'm adding the button
}
View::View(QWidget *parent) : QWidget(parent)
{
//Layout
}
void View::setController(Controller *c){
controller = c;
connect(startButton, SIGNAL(clicked()), controller, SLOT(begin()));
//ERROR controller is a Controller* and it can't be converted it to const QObject*
}
And this is the Controller class
class Controller : public QObject
{
Q_OBJECT
private:
QTimer* timer;
View* view;
Model* model;
public:
explicit Controller(QObject *parent = nullptr);
~Controller();
void setModel(Model* m);
void setView(View* v);
public slots:
void begin() const;
};
#endif // CONTROLLER_H
And the methods
Controller::Controller(QObject *parent):
QObject(parent), timer(new QTimer)
{
connect(timer, SIGNAL(timeout()), this, SLOT(next()));
}
Controller::~Controller() { delete timer; }
void Controller::setModel(Model* m) { model = m; }
void Controller::setView(View* v) { view = v; }
void Controller::begin() const {
timer->start(200);
}
For good measure, here is the main where I set each component
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
View w;
Controller c;
Model m;
c.setModel(&m);
c.setView(&w);
w.setController(&c);
w.show();
return a.exec();
}
I've tried everything I could think of, can't make it work..
Stop using the terrible text-based slot connection interface.
Use the modern one that gives nice compile errors:
QObject::connect(startButton, &QPushButton::clicked, controller, &Controller::begin);
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
I need some advice to access the field(QString name) variable in QWizardPage from a QThread. I'm building some kind of an installer and I want to do the installing work in a separate Thread.
My purpose:
When reached the commit/install page, I want to execute code to do the "installing" and update the QWizardPage with my progress, until its finished.
The install function is dependent on many field() variables from other QWizardPages. Therefore I tried to execute this install function from a QThread, which is defined in an inner class from my QWizardPage. The problem is, the field()-function i a non-static member and so it's not working. And so I'm out of ideas to run my install-function parallel to my WizardPage.
I tried something like this:
InstallPage.h
class InstallPage : public QWizardPage
{
Q_OBJECT
class WorkerThread : public QThread
{
Q_OBJECT
void run() override;
};
public:
InstallPage(QWidget *parent = 0);
private:
QLabel *lProgress;
WorkerThread *installer;
void install();
};
InstallPage.c
InstallPage::InstallPage(QWidget *parent)
: QWizardPage(parent)
{
...
installer = new WorkerThread(this);
installer->start();
}
void InstallPage::WorkerThread::run()
{
if(field("checkBox1").ToBool())
{
doStuff();
}
}
//QT-Creator says at field("checkBox1"):
//error: call to non-static member function without an object argument
I'm also open for any other idea to make my installer work. Maybe someone knows something I haven't thought of.
Another approach is to create a worker (QObject) that lives in another thread that performs the heavy task and notifies the status of that task through signals:
#include <QtWidgets>
class InitialPage: public QWizardPage
{
public:
InitialPage(QWidget *parent = nullptr): QWizardPage(parent)
{
QSpinBox *spinbox = new QSpinBox;
QLineEdit *lineedit = new QLineEdit;
QVBoxLayout *lay = new QVBoxLayout(this);
lay->addWidget(spinbox);
lay->addWidget(lineedit);
registerField("value1", spinbox);
registerField("value2", lineedit);
}
};
class InstallWorker: public QObject
{
Q_OBJECT
public:
InstallWorker(QObject *parent=nullptr): QObject(parent)
{
}
public Q_SLOTS:
void install(int param1, const QString & param2)
{
Q_EMIT started();
for(int i=0; i < 100; i++){
qDebug() << __PRETTY_FUNCTION__ << i << param1 << param2;
QThread::msleep(100);
Q_EMIT progressChanged(i);
}
qDebug()<< __PRETTY_FUNCTION__ << "finished";
Q_EMIT finished();
}
Q_SIGNALS:
void started();
void progressChanged(int value);
void finished();
};
class InstallPage: public QWizardPage
{
Q_OBJECT
public:
InstallPage(QWidget *parent = nullptr): QWizardPage(parent),
label(new QLabel), progressbar(new QProgressBar)
{
QVBoxLayout *lay = new QVBoxLayout(this);
lay->addWidget(label);
lay->addWidget(progressbar);
progressbar->setMinimum(0);
progressbar->setMaximum(100);
thread = new QThread(this);
worker.moveToThread(thread);
connect(&worker, &InstallWorker::started, this, &InstallPage::onStarted);
connect(&worker, &InstallWorker::finished, this, &InstallPage::onFinished);
connect(&worker, &InstallWorker::progressChanged, this, &InstallPage::onProgressChanged);
thread->start();
}
~InstallPage(){
thread->quit();
thread->wait();
}
void initializePage(){
start_install();
}
private Q_SLOTS:
void start_install(){
int param1 = field("value1").toInt();;
QString param2 = field("value2").toString();
QMetaObject::invokeMethod(&worker, "install", Qt::QueuedConnection, Q_ARG(int, param1), Q_ARG(QString, param2));
}
void onStarted(){
for(QWizard::WizardButton which: {QWizard::BackButton, QWizard::NextButton, QWizard::CancelButton})
if(QAbstractButton * button = wizard()->button(which))
button->setEnabled(false);
}
void onFinished(){
for(QWizard::WizardButton which: {QWizard::BackButton, QWizard::NextButton, QWizard::CancelButton})
if(QAbstractButton * button = wizard()->button(which))
button->setEnabled(true);
wizard()->next();
}
void onProgressChanged(int value){
progressbar->setValue(value);
label->setNum(value);
}
private:
InstallWorker worker;
QThread *thread;
QLabel *label;
QProgressBar *progressbar;
};
class FinalPage: public QWizardPage
{
public:
FinalPage(QWidget *parent = nullptr): QWizardPage(parent)
{
}
};
#include "main.moc"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWizard wizard;
wizard.addPage(new InitialPage);
wizard.addPage(new InstallPage);
wizard.addPage(new FinalPage);
wizard.show();
return app.exec();
}
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
});