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.
Related
I need to know what am I doing wrong.
I tried researching about it but I can't really find anything that it's related to my case. I am new to QT and debugging signal and slots is kinda technical for me.
What I wanted to do is just simple: make a thread that will continuously send signal to my QProgressBar widget.
Here's my essential code snippets:
thread.h
class MyThread : public QThread
{
public:
MyThread(QWidget * parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
MyThread * test = new MyThread(this);
connect(test,SIGNAL(valueChanged(int)),ui->progressBar,SLOT(setValue(int)));
test->start();
}
thread.cpp
MyThread::MyThread(QWidget * parent)
{
}
void MyThread::run(){
emit valueChanged(10); //for simplicity
}
void MyThread::valueChanged(int value){
}
I only have a single progressBar on my UI and my main is the same as the default.
Anyway, upon running of the code. I kept on getting this no such signal from my thread class. May I know what am I doing wrong?. I would also like to clarify if my understanding is right regarding signals and slots in my own words: it means that the slot will be triggered everytime the signal is called.
I believe the error message is due to a missing Q_OBJECT macro at the top of your MyThread declaration. The documentation at http://doc.qt.io/qt-5/signalsandslots.html explains this is necessary for any class that wants to declare signals and slots.
Change your class definition to:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QWidget * parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
};
Take a look at the linked documentation, specifically the A Small Example section, for a complete explanation why this is needed.
You must not implement a signal in a .cpp file. MOC will do that and there must only be one implementation.
Just delete this part:
void MyThread::valueChanged(int value){
}
If your code works, that might be luck because the linker throws away the right implementation. You should not rely on that.
I am trying to create a thread for a Scanner class which handles all the events for this particular class, thereby freeing the GUI thread. I have an exit button on my GUI which simply calls qApp->quit() to exit the application, but I am not sure how to deal with the thread in my Scanner class. I am seeing the following errors in the debug log when the application is exited.
QThread::wait: Thread tried to wait on itself
QThread::wait: Thread tried to wait on itself
QThread: Destroyed while thread is still running
In Scanner.cpp (Omitted other functions)
Scanner::Scanner() :
{
this->moveToThread(&m_thread);
connect(&m_thread, &QThread::finished, this, &QObject::deleteLater);
connect(this, SIGNAL(StartEnroll()), this, SLOT(StartEnrollment()));
m_thread.start();
}
Scanner::~Scanner()
{
m_thread.quit(); // Not sure if this is the correct
m_thread.wait();
}
In main Window.cpp (Omitted other functions)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->ExitButton, SIGNAL(released()), this, SLOT(Quit()));
connect(&m_scanner, SIGNAL(FinishedEnroll(bool)), this, SLOT(EnrollDone(bool)));
}
void MainWindow::Quit()
{
close();
qApp->quit();
}
Any pointers on how to quit safely quit the application in a multi-threaded application.
You need to let the Scanner class know that the application is exiting.
Add the following line to the constructor of MainWindow
connect(qApp, SIGNAL(aboutToQuit()), &m_scanner, SLOT(deleteLater()));
UPDATE:
connect(&m_thread, &QThread::finished, this, &QObject::deleteLater);
Should not be in the constructor of Scanner
and
m_thread.quit();
m_thread.wait();
should not be in the destructor of Scanner
In fact, m_thread should not be part of Scanner in any way. The QThread class does not represent a thread, it is a thread manager and should be owned and controlled from the thread where it was created.
There are a number of methods of using threads in Qt, many not documented very well. If you want to use the
workerObject->moveToThread(&thread);
thread.start();
way of using threads, then m_thread should be a member of MainWindow class and these function calls should be made in it's constructor.
Thanks for clarifying and for the solutions posted above. Here is what I did based on what was posted before.
ScannerThread.h
#include <QThread>
class ScannerThread : public QThread
{
public:
ScannerThread();
~ScannerThread();
};
ScannerThread.cpp
#include "scannerthread.h"
ScannerThread::ScannerThread()
{
connect(this, &QThread::finished, this, &QObject::deleteLater);
}
ScannerThread::~ScannerThread()
{
quit();
wait();
}
In MainWindow.h
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void Quit();
private:
Ui::MainWindow *ui;
Scanner m_scanner;
ScannerThread m_scannerThread;
};
In MainWindow.cpp (Omitting other functions)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_scanner.moveToThread(&m_scannerThread);
m_scannerThread.start();
connect(ui->ExitButton, SIGNAL(released()), this, SLOT(Quit()));
connect(qApp, SIGNAL(aboutToQuit()), &m_scanner, SLOT(deleteLater()));
}
void MainWindow::Quit()
{
close();
qApp->quit();
}
This seemed to work fine for me. If you see any errors please correct, and thanks for helping with this.
First you should move your QThread out of the Scanner class. A QThread manages a thread, so you can't call functions that are related to the thread management inside that thread itself. That's the reason you're getting the message about the thread waiting on itself.
You should rather have something like that:
m_scanner.moveToThread(&m_thread);//make the thread a member of your window
m_thread.start();
Then, in your quit function, do as you want, either waiting on the thread (better) or terminating it (worse) before exiting, or a tradeoff, such as:
void MainWindow::Quit()
{
close();
//Wait maximum 1 second
if(!m_thread.wait(1000) {
m_thread.terminate();
}
qApp->quit();
}
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).
I have a qslider to control the zooming of a map like this:
connect(ui->zoomSlider, SIGNAL(valueChanged(int)), ui->map, SLOT(SetZoom(int)));
However, because this online-map response relatively slow.
I found that the qslider's response also becomes very slow which means when you slide the slider, it's position won't change until suddenly it jump to the position where you release your mouse.
How could I solve this?
One possible solution to delay processing of your signal is to connect it with slot by using Qt::QueuedConnection.
connect(ui->zoomSlider, SIGNAL(valueChanged(int)), ui->map, SLOT(SetZoom(int)), Qt::QueuedConnection);
With Qt::QueuedConnection emitted valueChanged signal event will be not processed at the time of generation, as it happens with directly connected signals. Event will be added to the event loop queue. This is how Qt::QueuedConnection is implemented inside Qt.
Specially for Nejat to test this approach it's possible to use following code:
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void signalReceived();
void signalReceivedQueued();
void buttonPressed();
signals:
void directConnectedSignal();
void queuedConnectedSignal();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this, SIGNAL(directConnectedSignal()), SLOT(signalReceived()), Qt::DirectConnection);
connect(this, SIGNAL(queuedConnectedSignal()), SLOT(signalReceivedQueued()), Qt::QueuedConnection);
connect(ui->pushButton, SIGNAL(pressed()), SLOT(buttonPressed()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::signalReceived()
{
qDebug() << "signalReceived";
}
void MainWindow::signalReceivedQueued()
{
qDebug() << "signalReceivedQueued";
}
void MainWindow::buttonPressed()
{
emit queuedConnectedSignal();
emit directConnectedSignal();
}
If you run code snippet above you will get following output on button press:
signalReceived
signalReceivedQueued
Queued signal is emitted first, but received last. And this can be used in your case to prioritize processing of emitted signals.
However most of all using of queued connection will not help you, because user emits slider event too frequently and UI will freeze in any case. So, I can suggest following:
Determine why exactly UI is freezes, what part of code freezing it.
Try to avoid freezing by asynchronous calls or by moving logic into separate thread, or by using QtConcurrent
If you really can't control the way how map is scaled in your webpage, try to ignore all events generated by the QSlider and react only on last generated in 500 ms interval, for example.
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 :)