qt qslider not smooth - c++

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.

Related

QNetworkAccessManager freezes GUI even when in another thread

When my program opens, a connection is made to my server via QNetworkAccessManager::connectToHostEncrypted() which is called in the constructor of MainWindow. This freezes the GUI thread and causes a noticeable delay until the connection is finished. (Sometimes over a full second longer)
This problem is worsened by the fact that my program fades in at startup, so while the GUI thread is blocked, the fade in doesn't start until after the connection is done. In a default Qt project, this is noticeable in other ways like widgets not being painted.
To keep the GUI thread going, I moved QNetworkAccessManager into a completely different thread with QThread thinking this would solve the issue, however the GUI thread still freezes. This makes no sense to me.
Here is a minimally compilable example project.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QThread>
class Connection : public QNetworkAccessManager
{
Q_OBJECT
public:
Connection(QObject *parent) : QNetworkAccessManager(parent){}
public slots:
void openConnection(){
connectToHostEncrypted("https://www.url.com");
}
signals:
void closeThread(bool);
};
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QThread *connectionThread;
Connection *connection;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connection = new Connection(this);
connectionThread = new QThread();
connection->moveToThread(connectionThread);
connect(connectionThread, SIGNAL(started()), connection, SLOT(openConnection()));
connect(connection, SIGNAL(closeThread(bool)), connectionThread, SLOT(quit()));
connect(connectionThread, SIGNAL(finished()), connectionThread, SLOT(deleteLater()));
connectionThread->start();
}
MainWindow::~MainWindow()
{
delete connection;
delete ui;
}
This example project creates an instance of Connection which is a subclass of QNetworkAccessManager that I then move to another thread via moveToThread(). This is how I do all my worker threads.
When the thread's start() signal is emitted, openConnection() calls connectToHostEncrypted() which is where the GUI thread freezes.
I have tried just calling a regular HTTP request instead, however the problem persists since an initial connection still needs to be made.
How come the GUI thread still freezes even though the connection is done in another thread?
The issue was I passed this as a parent to the Connection instance which meant moveToThread() couldn't be completed. I just had to check the output log to see that, but I must have missed it!
By removing that parent, the connection was now in it's own thread.
I further tested this by calling QThread::sleep(3) inside that openConnection() call and there was still no delay.
try to use :
connect(connectionThread, SIGNAL(started()), connection, SLOT(openConnection(),Qt::QueuedConnection);

what leads to the different outcome of the synchronously block function `sleep` in GUI and non GUI program

I use synchronously block QThread::sleep() function to do timing, which shows number one after another by the time.
the expected running process is synchronously block current thread 2 seconds, and run the following code to change displayed number, and synchronously block another 2 seconds, and so on..., the thought works well in non GUI program.
but in GUI mode, the label only show 9, which is the last number to be displayed.
what leads to the different outcome of the synchronous blocking function sleep in GUI and non GUI program?
#include <windows.h>
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QThread>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
//slot of start timing button
void Widget::on_pushButton_2_clicked()
{
for(int i=0;i<10;i++){
QThread.sleep(2);
ui->label->setText(QString::number(i));
}
}
The GUI needs to continually verify events such as the mouse, the keyboard, etc. and perform actions if certain conditions are met, that is called eventloop. In the case of sleep() it is a blocking task that does not allow the eventloop to run, generating the GUI to freeze (if you want to verify it, try to change the size of the window), so inside the GUI thread you should avoid to use that kind of functions, the blocking tasks you have to turn them into asynchronous or execute it in another thread.
But the task of the sleep() can be replaced by a QTimer without blocking the GUI:
*.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QTimer>
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_2_clicked();
void onTimeout();
private:
Ui::Widget *ui;
int counter;
QTimer timer;
};
#endif // WIDGET_H
*.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
counter = 0;
connect(&timer, &QTimer::timeout, this, &Widget::onTimeout);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_2_clicked()
{
timer.start(2000);
}
void Widget::onTimeout()
{
ui->label->setText(QString::number(counter));
counter++;
if(counter > 10){
counter = 0;
timer.stop();
}
}
Another option is to use QEventLoop with QTimer:
void Widget::on_pushButton_2_clicked()
{
for(int i=0;i<10;i++){
QEventLoop loop;
QTimer::singleShot(2000, &loop, &QEventLoop::quit);
loop.exec();
ui->label->setText(QString::number(i));
}
}
Update:
what leads to the different outcome of the synchronous blocking function sleep in GUI and non GUI program?
If you are creating a non GUI application using Qt you will also have problems, although the effect may be less visible.
In the case of the GUI as I said there is an eventloop that handles events, and among them that of repainting, I mean when you set the new text in the QLabel, this is not painted automatically but Qt decides the right moment. That's why when you use QThread::sleep() you do not have time to update the painting.
Obviously in a non GUI application, the eventloop does not verify many events as the one painted by it does not see the effect, in fact in a script that only prints numbers it does not verify any event.
To notice the problem, let's use the following example:
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [](){
qDebug()<< "hello world";
});
timer.start(1000);
qDebug()<< "start blocking";
QThread::sleep(10);
qDebug()<< "end blocking";
return a.exec();
}
We will see that nothing is printed until the sleep() ends, that is, blocking the eventloop that allows the QTimer to do its work.
Answering your comment:
but what still makes me puzzled is why after finishing executing sleep function, after stopping blocking current thread, the following codes can't run as normal
ui->label->setText(QString::number(i)); this statement, right after sleep function
Asynchronous tasks such as painting have less priority than synchronous tasks, that is to say first Qt will execute the for loop and then just do the asynchronous tasks, so in the for the variable that stores the QLabel text is updated, that is to say 0, 1 , ..., 9, and after that, the task is handed over to the eventloop so that it just paints the last value, that is, the 9.
Note:
You can force the evenloop to update within synchronous execution with QXXXApplication::processEvents(), but this is often considered a bad practice, I only show it so you know it but avoid using it:
for(int i=0;i<10;i++){
QThread.sleep(2);
ui->label->setText(QString::number(i));
QApplication::processEvents();
}

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 :)

Automatically updating QDateTimeEdit so that it displays the current system date and time

Using the Qt library, is there a way to automatically update a QDateTimeEdit using a signal such that the widget shows the current date and time in a similar fashion to a clock?
In the code sample below, dateTimeEditSystem is the QDateTimeEdit object. However, the setDateTime() function only operates once. I would like the QDateTimeEdit object to dynamically update. Is there a reliable way of doing this without using a timer (i.e. with signals and slots)? Or is a timer the only way of doing this?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// setup the UI
ui->setupUi(this);
// set the current date and time
ui->dateTimeEditSystem->setDateTime( QDateTime::currentDateTime() );
}
I tried using a timer, but unfortunately the QDateTimeEdit did not update. Here is the complete mainwindow.cpp code. What am I doing wrong here?
#include <QTimer>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->dateTimeEditSystem->setDateTime( QDateTime::currentDateTime() );
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT( updateTime() ));
timer->start(1000);
}
void MainWindow::updateTime()
{
ui->dateTimeEditSystem->setDateTime( QDateTime::currentDateTime() );
}
MainWindow::~MainWindow()
{
delete ui;
}
UPDATE:
This is actually very easy to do. The reason why the code was not updating was due to the lack of a slot declaration in the mainwindow.h file. Here is the complete contents of the mainwindow.h header.
#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:
Ui::MainWindow *ui;
private slots:
void updateTime();
};
#endif // MAINWINDOW_H
Automatically updating a QDateTimeEdit or any other clock widget within Qt is easily accomplished with a QTimer. Refer to the following examples for how to accomplish this:
http://qt-project.org/doc/qt-4.8/widgets-digitalclock.html
OR
http://qt-project.org/doc/qt-4.8/widgets-shapedclock.html
Note that the resolution of a QTimer varies on different operating systems, but for updates that need to occur ~1 second at a time, a QTimer should be fine on virtually all platforms. Refer to the following for more information on the resolution of QTimer:
http://qt-project.org/doc/qt-4.8/QTimer.html#accuracy-and-timer-resolution