I'm trying to get the QTimer running, but it never triggers.
I found some other questions about the timer, but the problem was always the timer being out of scope. This is not the case in my small example:
I create the timer in a custom QMainWindow, this is the .h file:
#include <iostream>
#include <QtWidgets/QMainWindow>
#include <QTimer>
class MyMainWindow : public QMainWindow {
Q_OBJECT;
private:
QTimer *mainTimer;
public slots:
void timerUpdate();
public:
MyMainWindow();
};
This is the .cpp file:
#include "MyMainWindow.h"
MyMainWindow::MyMainWindow() {
QMainWindow();
mainTimer = new QTimer(this);
connect(mainTimer, SIGNAL(timeout()), this, SLOT(update()));
mainTimer->start(1000);
std::cout << "Timer created.\n";
}
void MyMainWindow::timerUpdate() {
std::cout << "test";
}
Finally, this is my main.cpp:
#include <QtWidgets/QApplication>
#include "MyMainWindow.h"
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
MyMainWindow mmw;
mmw.show();
return app.exec();
}
When I execute this code, I only get "Timer created." and never "test".
Any suggestions?
You're connecting to SLOT(update()), but your function is called timerUpdate.
Using more modern Qt 5 signal-slot connection syntax, that would never have happened and you'd get an error at compile-time. You should prefer using that.
Related
I wanted to create a Qt widget which communicates with other classes on different threads via the signal / slot system. The recieving Objects are created in a Function wich is run via std::async.
The problem is: If the widget emits a signal the slot on the other thread is not called.
My Example:
I created the Class MainWindow which derives from QMainWindow and will live on the main thread. The class Reciever is created in a function which is called via std::async, and has a thread which should print something to the console.
I tested if the signal is emitted by connecting it to another slot on the same thread which works fine.
MainWindow.hpp
#pragma once
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
signals:
void send();
private slots:
void buttonClicked();
void recieve();
};
MainWindow.cpp
#include "MainWindow.hpp"
#include <iostream>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QPushButton* start = new QPushButton("Start");
setCentralWidget(start);
start->show();
connect(start, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
connect(this, SIGNAL(send()), this, SLOT(recieve()));
}
void MainWindow::buttonClicked()
{
std::cout << "MainWindow::buttonClicked()\n";
emit send();
}
void MainWindow::recieve()
{
std::cout << "MainWindow::recieve()\n";
}
Reciever.hpp
#include <QObject>
class Reciever : public QObject
{
Q_OBJECT
public:
Reciever(QObject *parent = 0);
public slots:
void recieve();
};
Reciever.cpp
#include "Reciever.hpp"
#include <iostream>
Reciever::Reciever(QObject *parent) : QObject(parent)
{
std::cout << "Reciever()" << std::endl;
}
void Reciever::recieve()
{
std::cout << "Reciever::recieve()" << std::endl;
}
main.cpp
#include "MainWindow.hpp"
#include "Reciever.hpp"
#include <QApplication>
#include <future>
void StartAndConnect(MainWindow &widget)
{
Reciever* rec = new Reciever();
QObject::connect(&widget, SIGNAL(send()), rec, SLOT(recieve()));
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow myWidget;
myWidget.show();
auto future = std::async(std::launch::async, [&myWidget](){
StartAndConnect(myWidget);
});
app.exec();
future.wait();
}
After some research my strongest guess was, that the thread launched by std::async does not has a Qt event-loop and thus will not come to a point where the posted event (emit) is processed. I changed the main to use QtConcurrent::run but it also did not work.
EDIT
Here my try with QtConcurrent:
main2.cpp
#include "MainWindow.hpp"
#include "Reciever.hpp"
#include <QApplication>
#include <future>
#include <QtConcurrent>
void StartAndConnect(MainWindow &widget)
{
Reciever* rec = new Reciever();
QObject::connect(&widget, SIGNAL(send()), rec, SLOT(recieve()));
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow myWidget;
myWidget.show();
auto future = QtConcurrent::run( [&myWidget](){
StartAndConnect(myWidget);
});
app.exec();
future.waitForFinished();
}
You need a running event loop in your thread, if you want to process cross-thread slot calls.
auto future = QtConcurrent::run( [&myWidget](){
StartAndConnect(myWidget);
QEventLoop e;
e.exec();
});
But I recomend to use QThread, because in your case it is obvious. Qt has a very good documentation, that describes your case.
I would like to create a class that has its own QTimer and QThread for some projects for Robot's sensors. After some searching, this is what I came up with
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QObject>
#include <QDebug>
//#####################( Robot Class )#########################3
class Robot : public QObject
{
public:
Robot(QObject *parent = 0);
~Robot();
private:
QTimer *mQTimer;
QThread *mQThread;
public slots:
void update();
};
Robot::Robot(QObject *parent)
: QObject(parent)
{
mQTimer = new QTimer(0);
mQThread = new QThread(this);
mQTimer->setInterval(1);
mQTimer->moveToThread(mQThread);
connect(mQTimer, SIGNAL(timeout()), this, SLOT(update()));
connect(mQThread, SIGNAL(started()), mQTimer, SLOT(start()));
mQThread->start();
//mQTimer->start();
}
Robot::~Robot()
{
delete mQTimer;
delete mQThread;
}
void Robot::update()
{
qDebug() << "Robot is updating ...";
}
//##################( Main )###########################
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Robot *myRobot = new Robot(0);
return a.exec();
}
I'm getting this error
QObject::connect: No such slot QObject::update() in ..\untitled1\main.cpp:34
QObject::connect: No such slot QObject::update() in ..\untitled1\main.cpp:34
You are missing the Q_OBJECT macro in your class also try to avoid naming the methods like that because you can mix it with Qt methods names. Also make additional header and cpp file for each class you create in this case make robtot.h and robot.cpp.
class Robot : public QObject
{
Q_OBJECT
public:
Robot(QObject *parent = 0);
~Robot();
...
The below works for me. You forgot the Q_OBJECT macro and to include the moc output that defines the static metadata for Robot.
There's of course no point to this code, since the Robot::update slot will execute in the main thread.
Your code has two threads: the main thread, where the Robot object lives, and the robot.mThread, where the timer lives. The timer will time out in the mThread, and will queue a slot call on the main thread. That slot call will end up invoking robot.update with a.exec on the stack.
Note that there's no need to explicitly have the timer and the thread allocated on the heap using new. They should be direct members of Robot, or of its PIMPL.
main.cpp
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>
class Robot : public QObject
{
Q_OBJECT
QTimer mTimer;
QThread mThread;
public:
Robot(QObject *parent = 0) : QObject(parent) {
connect(&mTimer, &QTimer::timeout, this, &Robot::update);;
mTimer.start(1000);
mTimer.moveToThread(&mThread);
mThread.start();
}
Q_SLOT void update() {
qDebug() << "updating";
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Robot robot;
return a.exec();
}
#include "main.moc"
It would make more sense to move the entire robot to its own thread. Note that when you do that, you need to set parentage on all objects owned by robot, so that they all switch threads along with the Robot object.
The Thread class fixes the long standing usability bug of QThread - it turns it into a truly RAII class that can be safely destructed at any time.
main.cpp
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>
class Thread : public QThread {
using QThread::run;
public:
~Thread() { quit(); wait(); }
};
class Robot : public QObject
{
Q_OBJECT
QTimer mTimer;
int mCounter;
public:
Robot(QObject *parent = 0) : QObject(parent), mTimer(this), mCounter(0) {
connect(&mTimer, &QTimer::timeout, this, &Robot::update);;
mTimer.start(1000);
}
Q_SLOT void update() {
qDebug() << "updating";
if (++mCounter > 5) qApp->exit();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Robot robot;
Thread thread;
robot.moveToThread(&thread);
thread.start();
return a.exec();
}
#include "main.moc"
i read other questions about the same issue but wasn't able to solve mine. When i run my code, the program starts, send QObject::connect: No such slot mywindow::changerLargeur(int) and then fails.
thanks you for your help
h file
#ifndef MYWINDOW_H
#define MYWINDOW_H
#include <QWidget>
#include <QSlider>
#include <QLCDNumber>
class mywindow : public QWidget
{
Q_OBJECT
public:
mywindow();
public slots:
void changerlargeur(int largeur);
private:
QSlider *glisseur;
QLCDNumber *afficheur;
};
#endif // MYWINDOW_H
cpp file
#include "mywindow.h"
mywindow::mywindow(): QWidget()
{
setFixedSize(200, 100);
glisseur = new QSlider(Qt::Horizontal,this);
glisseur->setRange(100,900);
glisseur->setGeometry(10, 60, 150, 20);
QObject::connect(glisseur, SIGNAL(valueChanged(int)), this, SLOT(changerLargeur(int)));
QObject::connect(glisseur, SIGNAL(valueChanged(int)), afficheur, SLOT(display(int)));
afficheur = new QLCDNumber(this);
afficheur->setSegmentStyle(QLCDNumber::Flat);
}
void mywindow::changerlargeur(intlargeur)
{
setFixedSize(largeur, 100);
}
main file
#include <QApplication>
#include "mywindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
mywindow fenetrep;
fenetrep.show();
return app.exec();
}
Like most other things in C++, Qt's signals and slots are case sensitive. So this won't work:
void changerlargeur(int largeur);
vs.
SLOT(changerLargeur(int))
You need to decide whether you want the L to be upper or lower case and stick with it.
Another issue is this:
QObject::connect(glisseur, SIGNAL(valueChanged(int)), afficheur, SLOT(display(int)));
afficheur = new QLCDNumber(this);
You can't connect to a slot on an object that doesn't exist yet.
I am aware that to use the signals and slots mechanism of Qt inside a class, the class must include the Q_OBJECT macro, but I am attempting to use signals and slots in main(), without using any class.
Here is my code so far:
#include <QApplication>
#include <QWidget>
#include <QTextEdit>
#include <QtGui>
void saveText();
int main(int argv, char **args)
{
QApplication app(argv, args);
QTextEdit textEdit;
QPushButton saveButton("Save!");
QPushButton exitButton("Exit!");
QObject::connect(&exitButton,SIGNAL(clicked()),qApp,SLOT(quit()));
QObject::connect(&saveButton,SIGNAL(clicked()),qApp,SLOT(saveText()));
QVBoxLayout vlyt;
vlyt.addWidget(&textEdit);
vlyt.addWidget(&exitButton);
vlyt.addWidget(&saveButton);
QWidget mainWindow;
mainWindow.setLayout(&vlyt);
mainWindow.show();
return app.exec();
}
void saveText()
{
exit(0);
}
Here is the GUI window generated:
From the above code, the exit button is connected to quit(), which is a Qt function, when clicked it works. The save button assigned to the function saveText(), is configured to exit, but does not do so.
Please tell me where I have gone wrong in understanding signals and slots in Qt.
Qt4...
All classes that inherit from QObject or one of its subclasses (e.g.,
QWidget) can contain signals and slots.1
So, you can not use slots where placed outside of QObject children.
You can connect signals to the slots which are in classes where derived from QObject. Put your slot in a class which is in a separated .h/.cpp file:
class MyClass : public QObject
{
Q_OBJECT
...
public slots:
void saveText();
};
According to Qt5: New Signal Slot Syntax in Qt 5. You can connect to those type of global functions. (Thanks to #thuga's comments)
I'll just put example here.
main.cpp:
#include <QCoreApplication>
#include <iostream>
#include <QObject>
#include "siggen.h"
void handler(int val){
std::cout << "got signal: " << val << std::endl;
}
int main(int argc, char *argv[])
{
SigGen siggen;
QObject::connect(&siggen, &SigGen::sgAction, handler);
siggen.action();
QCoreApplication a(argc, argv);
std::cout << "main prog start" << std::endl;
return a.exec();
}
siggen.h:
#ifndef SIGGEN_H
#define SIGGEN_H
#include <QObject>
class SigGen : public QObject
{
Q_OBJECT
public:
explicit SigGen(QObject *parent = 0);
void action(void);
signals:
void sgAction(int value);
};
#endif // SIGGEN_H
siggen.cpp:
#include "siggen.h"
SigGen::SigGen(QObject *parent) : QObject(parent)
{}
void SigGen::action()
{
emit sgAction(42);
}
QObject::connect(&saveButton, &QPushButton::clicked, [](){saveText();}); // qt5.9.6
or as mentioned in the masoud's answer
QObject::connect(&saveButton, &QPushButton::clicked, saveText); // qt5.9.6
It is possible to connect a signal to function inside main function.
This has been tested in Qt5.15. Here is the simple example where the QPushButton 'Clicked' signal is used to trigger a function (here I used lamda's, but regular functions can also be used).
int main(int argc, char *argv[])
{
// Created QApplication
QApplication a(argc, argv);
// Created the splashscreen(which is QObject)
QPixmap pixmap(":/images/Sample.png");
QSplashScreen splash(pixmap);
// Created the pushbutton and added to splashscreen
QPushButton b(&splash);
b.setGeometry(50,50, 100, 50);
b.setText("FPS");
// variable to be modified inside a lamda function
int i = 0;
// Connection for button clicked signal executes lamda function
QObject::connect(&b, &QPushButton::clicked,
[i = static_cast<const int&>(i), &splash = static_cast<QSplashScreen&>(splash)]()mutable
{i = i+1; splash.showMessage("clicked: "+ QString::number(i));});
// Adding properties and displaying the splashscreen
splash.setGeometry(0,0, 1920, 1080);
splash.setEnabled(true);
splash.show();
a.processEvents();
return a.exec();
}
I'm trying to create a simple game that uses a timer but I can't seem to get it working. It throws this error: "no matching function for call to 'QObject::connect(QTimer*&, const char*, Time*&, const char*)'" now matter what I do do I can't fix it please help. I have only just started coding the game when I ran into this error. Here are the files exluding the unimportant(at the moment) qml file.
Main.cpp:
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
#include "time.h"
#include <QObject>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationLockLandscape);
viewer.setMainQmlFile(QLatin1String("qml/RaakGame/main.qml"));
viewer.showExpanded();
Time *timmer = new Time;
QTimer *timer = new QTimer(0);
QObject::connect(timer, SIGNAL(timeout()), timmer, SLOT(ShowTime()));
timer->start(1000);
return app.exec();
}
time.h:
#ifndef TIME_H
#define TIME_H
class Time
{
public:
Time();
private slots:
void ShowTime();
signals:
int setTime();
};
time.cpp:
#include "time.h"
int theTime = 60;
Time::Time()
{
ShowTime();
}
void Time::ShowTime()
{
theTime--;
}
int Time::setTime()
{
return theTime;
}
#endif // TIME_H
Your implementation of Time does not declare it to be a QObject, so you can't not connect slots or signals from it. You need to inherit from QObject (or probably QWidget if you want to draw on the screen) and then include the statement Q_OBJECT which instantiates a few needed things.
class Time : public QWidget
{
Q_OBJECT
public:
Time();
private slots:
void ShowTime();
signals:
int setTime();
};
I notice that your classes do not contain the Q_OBJECT macro defined. This may help your efforts.
class Time
{
Q_OBJECT
public Time()
.
.
.
}