Qt: how to call function at a certain frequency? [duplicate] - c++

I know my question is similar to this QUESTION but i cant find solution from there. Can anyone give a breif answer to my problem?
I have a function like this
void myWidget::showGPS()
{
/* This function will read data from text file
that will continuouly change over time
then process its data */
}
I want to call this function every 15-20 seconds without using Quick-and-dirty method of setting boolean to true .
Is there any way to implement this using
QT signal and slot with timer or something like that

The method showGPS(), should be made a slot of MyWidget class.
Then on, its just a matter of using the QTimer class.
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), myWidget, SLOT(showGPS()));
timer->start(15000); //time specified in ms
The above code will call showGPS(), every 15 seconds.
Since the call is periodic, you don't have to set the timer in one shot mode using the setSingleShot() method.
Edit:
This is a simple poc, to help you understand it..
#include <QApplication>
#include <QtGui>
#include <qobject.h>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget()
{
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(showGPS()));
timer->start(1000); //time specified in ms
}
public slots:
void showGPS()
{
qDebug()<<Q_FUNC_INFO;
}
private:
QTimer *timer;
};
int main(int argc, char **args)
{
QApplication app(argc,args);
MyWidget myWidget;
return app.exec();
}

While you can use QTimer for checking file changes, in your case QFileWatcher might be better solution.

Related

Why do I get non-object type 'char *(const char *, int) throw()' is not assignable

I implemented a minimal verifiable example below that replicates the issue.
The problem I have is after that a QLabel count down arrives to 00:00, I would like the application to shut down automatically. But this is not happening and I obtain from compiler the following error:
non-object type 'char *(const char *, int) throw()' is not assignable
Below the minimal verifiable example code
mainwindow.h
#include <QMainWindow>
#include <QTime>
#include <QTimer>
#include <QProcess>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void stopAtZeroCountDown();
public slots:
void timerUpdate();
private:
Ui::MainWindow *ui;
QTimer *timer;
QTime time;
QProcess *stopAtZero;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
stopAtZeroCountDown();
ui->countDown->setText("1:00");
time.setHMS(0,1,0);
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
timer->start(1000);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::stopAtZeroCountDown()
{
this->stopAtZero = new QProcess(this);
this->stopAtZero->setProcessChannelMode(QProcess::MergedChannels);
connect(this->stopAtZero, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
[this](int exitCode, QProcess::ExitStatus exitStatus){
qDebug() << "[EXEC] FINISHED: " << exitCode << exitStatus;
index = ui->countDown->setText("00:00"); // <-- Error here
if(&index)
{
this->stopAtZero->start(QStringLiteral("/bin/sh"), QStringList() << QStringLiteral("/path/to/shutdown_executable.sh"));
};
});
}
void MainWindow::timerUpdate()
{
time = time.addSecs(-1);
ui->countDown->setText(time.toString("mm:ss"));
}
Below the compilation error, and also here
/home/emanuele/catkin_docking_ws/src/lidarlauncher/src/lidarlauncher/mainwindow.cpp:
In lambda function:
/home/emanuele/catkin_docking_ws/src/lidarlauncher/src/lidarlauncher/mainwindow.cpp:113:40: error: could not convert
‘this->MainWindow::ui->Ui::MainWindow::<anonymous>.Ui_MainWindow::labelCountDown->QLabel::setNum(0)’
from ‘void’ to ‘bool’
if(ui->labelCountDown->setNum(00))
EDIT_2
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//ui->countDown->setText(time.toString("hh:mm:ss"));
ui->countDown->setText("1:00");
//ui->countDown->setText(time.toString("mm:ss"));
time.setHMS(0,1,0);
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
timer->start(1000);
connect(this->stopAtZero, &QProcess::readyReadStandardOutput, [this, script = this->stopAtZero](){
QString s = QString::fromUtf8(script->readAll());
qDebug() << "[EXEC] DATA: " << s;
if (ui->countDown->setText("00:00")) { // <-- error here
this->stopAtZero->start(QStringLiteral("/bin/sh"), QStringList() << QStringLiteral("/home/emanuele/catkin_docking_ws/src/lidarboatsproject/stop_lidar_deck_and_gui.sh"));
}
});
}
So far I consulted the following source to help me solve the problem but without success.
I know that the problem is caused by an assignment that should be a QString as I am trying to capture the 00:00 format of the timer.
I also consulted this, this and those are all clear examples to me, with the only difference that here I am using qt components such as in this case a QLabel, it might be a simple error but I am getting a bit confused.
Thanks for pointing to the right direction for solving this issue.
You seem to have some code that look like this:
If you read the Qt documentation for QLabel::setText correctly, you'll see that there is a problem with the code you presented.
The Qt documentation says that the setText returns void. In other words, that function return nothing.
Yet, you try to get the result of the function to test in the if statement:
// call to setText
// v-----------------------------v
if (ui->countDown->setText("00:00")) {
// ...
}
What the compiler sees is something like this:
if (/* expression that returns void */) {
// ...
}
This is not valid. You cannot do if (void()). What would it even do?
Whatever you're trying to test with this if statement, it will have to be done another way.
I will try to guess what you're trying to do for the following, so it may be less accurate.
My guess is that you're trying to test if the countdown is equal to 00:00 in order to shutdown. Let me help you there.
You want to execute something when the timer has finished. This should be done in your timer update member function:
void MainWindow::timerUpdate()
{
time = time.addSecs(-1);
ui->countDown->setText(time.toString("mm:ss"));
// Check if we have a zero time on this tick
if (time == QTime(0, 0)) {
// put your code into the shutdown_function to make the shutdown
shutdown_function();
}
}
Here in each ticks, we test if the time is equal to a zero time. When it is, we proceed to execute the shutdown function.
You forgot to declare index as a variable.
There is a function index somewhere in scope and your compiler thinks you're trying to assign to it, which you can't do.
Furthermore, if (&index) makes no sense, as every variable that exists has a non-null address.
I suggest you review your library's documentation for setText to see what value it returns, and how to use that value… if it returns a value at all (which would be weird for a setter).

Substitute for sleep function in Qt/C++

So I am writing a program that displays each letter of a word for 1 second with a 1 second interval between the letters. (It's for a spelling exercise for grade 1). I am currently using the sleep function to "pause" the program for 1 second before it "updates" again. After that it displays the word for a second and then removes it. I repaint before the sleep function, else it does not seem to update in time.
Here is the basic function:
QString word = "apple";
QThread thread;
for(int i = 0; i < word.size(); i++)
{
ui->label1->setText(word[i]);
ui->label1->repaint();
thread.sleep(1);
ui->label1->setText("");
thread.sleep(1);
}
ui->label1->setText(word);
ui->label1->repaint();
thread.sleep(1);
ui->label1->setText("");
This works fine, except the program stops responding (even though I can see the correct output is still displaying) until the whole function is done executing then it works fine again. Is there another way I can accomplish this goal without using sleep? I am quite new to Qt.
Update I made. I made a new class that will handle the timer, but it does not seem to actually connect the signal and slot. Here is the .h file:
#ifndef TIMERDISPLAY_H
#define TIMERDISPLAY_H
#include <QTimer>
#include <QObject>
class TimerDisplay:public QObject
{
Q_OBJECT
public:
TimerDisplay();
public slots:
void expired();
private:
QTimer timer;
};
#endif // TIMERDISPLAY_H
and the .cpp file:
#include "timerdisplay.h"
#include <QDebug>
TimerDisplay::TimerDisplay()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(expired()));
timer.setSingleShot(false);
timer.setInterval(1000);
timer.start();
}
void TimerDisplay::expired()
{
qDebug()<<"timer expired";
}
Use QTimer or QElapsedTimer if you need more precision.
main.cpp
#include <QTimer>
#include <QCoreApplication>
#include <QString>
#include <QTextStream>
#include <QDebug>
int main(int argc, char **argv)
{
QCoreApplication application(argc, argv);
QTimer timer;
QTextStream textStream(stdout);
QString word = "apple";
int i = 0;
QObject::connect(&timer, &QTimer::timeout, [&textStream, word, &i] () {
if (i < word.size()) {
textStream << word.at(i) << flush;
++i;
}
});
timer.start(1000);
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
apple
This is happening, because you're blocking the thread. In most cases you're interested in using event loop.
You can use timer and increment a counter in a slot function. Every QObject has support for timer. You can start it using int QObject::startTimer(int interval) and it will call virtual void timerEvent(QTimerEvent *event) every interval miliseconds (it's a virtual method - reimplement it).
You can also use QTimer and connect QTimer::timeout() signal to accomplish the same thing.
Inside timer handler increment a counter and print the character.
It's a good idea to put your hands on finite state machine concept. FSMs are a great tool for solving similar problems problems. In fact, using a timer callback you create a state machine, but very simple one.
I still don't know what the problem is, but I found a make-shift solution. In my program I include one class (eg class1) into my mainwindow.cpp and from that class I include the timer class. I solved the problem by removing the timer class and adding all those functions to class1. Doesn't make sense to me, but it works.

Continuous warning sound in Qt?

What is the easiest way to play a continuous warning sound that lasts several minutes without affecting the main thread's performance?
I know that QSound can work in asynchronous mode, however, according to here:
Qt: How to play sound witout blocking main thread?
QSound would still bring noticeable affect on the main thread.
Is there any simple solution to this?
As suggested earlier, try to play sound in another thread. But QSound has not enough signals to control it. If you want get deeper control you can use QSoundEffect Try this:
header:
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
signals:
public slots:
void process();
};
#endif // WORKER_H
Cpp
#include "worker.h"
#include <QSound>
Worker::Worker(QObject *parent) :
QObject(parent)
{
}
void Worker::process()
{
QSound *sound = new QSound("path");
sound->setLoops(100);
sound->play();
}
Usage:
QThread *thr = new QThread;
Worker * work = new Worker;
connect(thr, SIGNAL(started()), work, SLOT(process()));
work->moveToThread(thr);
thr->start();
To play it several minutes you can set infinite number of loops and use QTimer (maybe singleShot) to end thread and delete object(music will be stopped too).

Simple digital clock by using Qt and QThread

I want to create a program by using Qt framework. The aim is to write a program which uses QThread to show a simple digital clock. but nothing happened when running.
This is the subclass of Qthread for running
paytamtimers.h
#ifndef PAYTAMTIMERS_H
#define PAYTAMTIMERS_H
#include <QThread>
class PaytamTimers:public QThread
{
Q_OBJECT
public:
PaytamTimers();
QString now;
protected:
virtual void run();
private:
QMutex mutex;
QThread *thread;
signals:
void mySignal(QString);
};
#endif // PAYTAMTIMERS_H
and this is the implementation of this.class
paytamtimers.cpp
#include "paytamtimers.h"
#include <QTime>
PaytamTimers::PaytamTimers()
{
this->now="";
this->thread=new QThread(0);
}
void PaytamTimers::run(){
forever{
mutex.lock();
this->now=QTime::currentTime().toString();
this->thread->sleep(1000);
emit mySignal(this->now);
mutex.unlock();
}
}
and this is the implementation of GUI form. This for consist of QLabel and an instance of paytamtimers,just for simplity
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "paytamtimers.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
t=new PaytamTimers();
t->start();
connect(t,SIGNAL(t->mySignal(QString)),this,SLOT(this->now(const QString &string)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::now(const QString &string){
this->ui->label->setText(t->now);
}
You should not hold the mutex while sleeping in the thread. In fact, your mutex is completely unnecessary.
Your connect statement is wrong, as noted by hyde. The this parameter is implied, so you could simply say:
connect(t, SIGNAL(mySignal(QString)), SLOT(now(QString)));
You don't need to use a thread in order to emit periodic time updates.
Your MainWindow could look like below. It'll take care to fire the timer event as close to full second as possible.
class MainWindow : public QWidget {
Q_OBJECT
QBasicTimer m_timer;
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) {
QTime t = QTime::currentTime();
m_timer.start(1000 - t.msec(), this);
// round to nearest second
if (t.msec() < 500) t = t.addMsecs(-t.msec()); else t = t.addMSecs(1000-t.msec());
now(t.toString());
}
}
void now(const QString &);
...
public:
MainWindow(QWidget *parent = 0) : QWidget(parent) {
m_timer.start(1000 - QTime::currentTime().msec(), this);
}
};
Your connect statement is wrong, it should be:
connect(t, SIGNAL(mySignal(QString)), this, SLOT(now(QString)));
To catch problems like this, first of all check console output, there you should see a warning about failing connect. And another thing, use Qt Creator autocompletion to fill in SIGNAL and SLOT macros, because it is very easy to make stupid mistakes, which will not be spotted by compiler.
There are a few other funny things, such as the seemingly useless extra QThread* member variable in your QThread subclass, and an unnecessary mutex, but these shouldn't stop things from working.
In general, it seems you're just learning Qt. I'd leave threads for later, they have a lot of small gotchas and details, and worrying about them while also learning the Qt basics will not make life easy.

Simple multithreading with Qt: am I doing this right?

I'm new to StackOverflow and wondering if I'm doing this right:
I'm writing a simple Qt application to test multi-threading (something I am also completely new to). I made a MainWindow that contains widgets, and a class MyThread that subclasses QThread and overrides the run() method.
The application simply displays two buttons, "Start Counter" and "Stop Counter", and a text field. When "start counter" is pressed, a worker thread is created and runs in the background, continuously incrementing a counter in a while loop and signaling the main thread (where the GUI is) with the updated value. When "Stop Counter" is pressed, a signal is sent to the main thread that stops the while loop, and the counter is stopped until "Start Counter" is pressed again.
This works perfectly fine ... but is it the best way? I'm new at this, and read a lot of people saying "don't subclass QThread" and other people saying "subclass QThread", and it's a little bit confusing. If this isn't the best way to implement this sort of thing (run a computationally-intensive loop in a background thread with "start" and "stop" buttons), what is? If I'm doing it wrong, how do I do it right? I don't want to learn the wrong way.
Thank you! And here's the code:
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public slots:
void stopRunning();
protected:
virtual void run();
signals:
void signalValueUpdated(QString);
private:
bool isRunning;
};
MyThread.cpp
#include "MyThread.h"
#include <QString>
void MyThread::run()
{
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
static int value=0; //If this is not static, then it is reset to 0 every time this function is called.
isRunning = 1;
while(isRunning == 1)
{
QString string = QString("value: %1").arg(value++);
sleep(1/1000); //If this isn't here, the counter increments way too fast and dies, or something; the app freezes, anyway.
emit signalValueUpdated(string);
}
}
void MyThread::stopRunning()
{
isRunning = 0;
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include "MyThread.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
//Widgets
QHBoxLayout * boxLayout;
QPushButton * startButton;
QPushButton * stopButton;
QLineEdit * lineEdit;
MyThread thread;
};
#endif
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
boxLayout = new QHBoxLayout(this);
startButton = new QPushButton("Start Counter", this);
stopButton = new QPushButton("Stop Counter", this);
lineEdit = new QLineEdit(this);
boxLayout->addWidget(startButton);
boxLayout->addWidget(stopButton);
boxLayout->addWidget(lineEdit);
qDebug("Thread id %d",(int)QThread::currentThreadId());
//When the start button is pressed, invoke the start() method in the counter thread
QObject::connect(startButton,SIGNAL(clicked()),&thread,SLOT(start()), Qt::QueuedConnection);
//When the stop button is pressed, invoke the stop() method in the counter thread
QObject::connect(stopButton,SIGNAL(clicked()),&thread,SLOT(stopRunning()), Qt::QueuedConnection);
//When the counter thread emits a signal saying its value has been updated, reflect that change in the lineEdit field.
QObject::connect(&thread,SIGNAL(signalValueUpdated(const QString&)),lineEdit,SLOT(setText(const QString&)), Qt::QueuedConnection);
}
Most of the time QThread sub-classing is a wrong way to do threading in Qt. I suggest you to read an article about threads, event loops and other which could give you an idea how to use threads in Qt in a better way. But do not listen to anyone who arguing that there is the only one right way to use QThread. There are 2 ways and while subclassing is not needed in general it could be useful sometimes. You just need to use non-subclassing way until you really need to subclass. In your particular case you don't need subclassing.
Replace sleep(1/1000); with msleep(100); Things will be just fine :)