There are two QListWidget with the same number of the items. How can synchronize their scrolling?
I mean when I scroll one of them, the other one should get same scrolling.
Suppose you have two QListWidget elements listWidget_1 and listWidget_2 in your UI, then you can use valueChanged/setValue signal/slot pair to connect vertical sliders of both listwidgets, indeed, I didn't find any issue of signals re-bouncing in this "two way" connection because eventually both values will be same and I think no more signals would be emitted, thus you can set such sufficient connections:
connect(this->ui->listWidget_1->verticalScrollBar(), &QScrollBar::valueChanged,
this->ui->listWidget_2->verticalScrollBar(), &QScrollBar::setValue);
connect(this->ui->listWidget_2->verticalScrollBar(), &QScrollBar::valueChanged,
this->ui->listWidget_1->verticalScrollBar(), &QScrollBar::setValue);
// test lists:
QList<QString> lw11, lw22;
for (int x=0; x <200; x++){
lw11.append("ListWidget1_" + QVariant(x).toString());
lw22.append("The Other lw is at: " + QVariant(x).toString());
}
this->ui->listWidget_1->addItems(lw11);
this->ui->listWidget_2->addItems(lw22);
If signal rebounce should be blocked anyway, then the model can be adjusted by adding a single slot to handle scrolling for both widgets and connect both to that slot:
connect(this->ui->listWidget_1->verticalScrollBar(),&QScrollBar::valueChanged
, this, &MainWindow::handleScroll);
connect(this->ui->listWidget_2->verticalScrollBar(),&QScrollBar::valueChanged
, this, &MainWindow::handleScroll);
and the slot logic can be :
void MainWindow::handleScroll(int value)
{
// Logic for detecting sender() can be used ... but I don't see it's important
// fast way to check which listWidget emitted the signal ...
if (this->ui->listWidget_1->verticalScrollBar()->value() == value){
qDebug() << "lw1 is in charge ...............";
disconnect(this->ui->listWidget_2->verticalScrollBar(), &QScrollBar::valueChanged,this, &MainWindow::handleScroll); // prevent signal rebounce from the other lw
this->ui->listWidget_2->verticalScrollBar()->setValue(value);
connect(this->ui->listWidget_2->verticalScrollBar(), &QScrollBar::valueChanged,this, &MainWindow::handleScroll);
}else{
qDebug() << "lw2 is in charge ...............";
disconnect(this->ui->listWidget_1->verticalScrollBar(), &QScrollBar::valueChanged,this, &MainWindow::handleScroll);
this->ui->listWidget_1->verticalScrollBar()->setValue(value);
connect(this->ui->listWidget_1->verticalScrollBar(), &QScrollBar::valueChanged,this, &MainWindow::handleScroll);
}
}
You must use the valueChanged() signal from the verticalScrollBar() of QListWidget, since the connection is bidirectional, it will cause unnecessary tasks to be executed for it using blockSignals():
In the next section I show an example:
#include <QApplication>
#include <QListWidget>
#include <QHBoxLayout>
#include <QScrollBar>
class Widget: public QWidget{
Q_OBJECT
QListWidget w1;
QListWidget w2;
public:
Widget(QWidget *parent=Q_NULLPTR):QWidget(parent){
auto layout = new QHBoxLayout{this};
layout->addWidget(&w1);
layout->addWidget(&w2);
connect(w1.verticalScrollBar(), &QScrollBar::valueChanged, [this](int value){
w2.verticalScrollBar()->blockSignals(true);
w2.verticalScrollBar()->setValue(value);
w2.verticalScrollBar()->blockSignals(false);
});
connect(w2.verticalScrollBar(), &QScrollBar::valueChanged, [this](int value){
w1.verticalScrollBar()->blockSignals(true);
w1.verticalScrollBar()->setValue(value);
w1.verticalScrollBar()->blockSignals(false);
});
for(int i=0; i<100; i++){
w1.addItem(QString("item %1 of 1").arg(i));
w2.addItem(QString("item %1 of 2").arg(i));
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "main.moc"
Related
I want to repeat the action performed in a SLOT until a qpushbutton is down.So I've done the following connections:
connect(ui->button,SIGNAL(pressed()),this,SLOT(button_hold()));
connect(ui->button,SIGNAL(released()),this,SLOT(button_released()));
and I've implemented the SLOTS in the following way
void My_class::button_hold(){
//CLASS ATTRIBUTE key_is_released , i
QThread::msleep(200);
int wait_lock = 500;
i++; //GOAL OF THE SLOT
QCoreApplication::processEvents(QEventLoop::AllEvents);
while(!key_is_released){
QThread::msleep(wait_lock);
i++;
cout<<i<<endl;
if(wait_lock > 50) wait_lock -= 50;
QCoreApplication::processEvents(QEventLoop::AllEvents);
}
key_is_released = false;
}
void My_class::button_released(){
key_is_released = true;
}
The goal is to repeat the action in the button_hod() Slot (In the example it's to increase i) even more quickly decreasing wait_lock and keeping the button down.The issue is that if i click button two times or more in a quick way the loop never ends,like if processEvents() would not work.The firts msleep is used in order to do not enter the loop (i is increased just once)if the button is just clicked and it is not keep down too long.If i do not click quickly but I keep down the button the method works well.
What am I doing wrong?
Reentering the event loop is a bad idea, and leads to spaghetti code.
Qt provides a wonderful state machine system with UML semantics. It's often best to model the system you're designing as a state machine. Here, there are two states: an idle state, and an active state: the value is incremented periodically while active.
The state machine decouples the Ui particulars (a button) from the core functionality: that of a periodically incrementing value.
Ideally, you would also factor out the state machine and the value to a controller class, and only connect the controller and the Ui from main() or a similar function.
// https://github.com/KubaO/stackoverflown/tree/master/questions/48165864
#include <QtWidgets>
#include <type_traits>
class Ui : public QWidget {
Q_OBJECT
int m_value = -1;
QStateMachine m_machine{this};
QState m_idle{&m_machine}, m_active{&m_machine};
QVBoxLayout m_layout{this};
QPushButton m_button{"Hold Me"};
QLabel m_indicator;
QTimer m_timer;
void setValue(int val) {
if (m_value == val) return;
m_value = val;
m_indicator.setNum(m_value);
}
void step() {
if (m_value < std::numeric_limits<decltype(m_value)>::max())
setValue(m_value + 1);
}
public:
Ui(QWidget * parent = {}) : QWidget(parent) {
m_layout.addWidget(&m_button);
m_layout.addWidget(&m_indicator);
m_machine.setInitialState(&m_idle);
m_idle.addTransition(&m_button, &QPushButton::pressed, &m_active);
m_active.addTransition(&m_button, &QPushButton::released, &m_idle);
m_machine.start();
m_timer.setInterval(200);
connect(&m_timer, &QTimer::timeout, this, &Ui::step);
connect(&m_active, &QState::entered, [this]{
step();
m_timer.start();
});
connect(&m_active, &QState::exited, &m_timer, &QTimer::stop);
setValue(0);
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Ui ui;
ui.show();
return app.exec();
}
#include "main.moc"
The problem was that clicking fast let say 10 times ,the release slot was called yet 10 times before entering in the loop, so key_is_released would be never updated again to true.Instead the button_hold slot was not yet been called for ten times.So adding a counter, increasing it in the button_hold slot and decreasing it in the release slot and adding a second condition counter>0 besides !key_is_released in the while loop fixes all.(It enters the loop only if not all the release slot have been run)
I'm learning the signals/slots in Qt and I have found a problem. I need to create my own slot that is called when items on QGraphicsScene (in QGraphicsView) are moved or selected.
I'm starting with a simple app that has one widget and on it is graphicsView and label. I've created a slot in my window and connected it to QGraphicsScene's signal, but it is not being used. Where is my mistake?
Here is the code:
//MainWindow.h
//as generated by QtCreator, just added one slot to it
...omitted for brevity...
public slots:
void selectedItemChanged(QGraphicsItem * newItem, QgraphicsItem * oldItem);
..omitted for brevity...
//------------------------------------------------------------------
//MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene * scene = new QGraphicsScene();
scene->setBackgroundBrush (QBrush(Qt::gray));
ui->graphicsView->setScene (scene);
for(int x = 10; x < 250; x+=20)
{
QGraphicsEllipseItem * item = scene->addEllipse (x,x,5,5,QPen(Qt::darkGreen),QBrush(Qt::darkGreen));
item->setFlag (QGraphicsItem::ItemIsFocusable,true);
}
QObject::connect (scene,SIGNAL(focusItemChanged),this,SLOT(selectedItemChanged));
}
void MainWindow::selectedItemChanged (QGraphicsItem *newItem, QGraphicsItem *oldItem)
{
qDebug()<<"called";
if(newItem == 0)
{
ui->label->setText ("Není vybrán bod");
}
else
{
ui->label->setText (QString::number (newItem->scenePos ().x ()) + "," + QString::number (newItem->scenePos ().y ()));
}
}
Now, when I run the probram it rins ok, but I cannot set Focus on the circles(ellipses) drawn on the scene and the slot is not used. I tried setting IsSelectable flag, but it does not help. Is there any other preferred way to get this done or solution to my problem?
You're not linking against the signal's right signature, according to the documentation:
void QGraphicsScene::focusItemChanged( QGraphicsItem * newFocus, QGraphicsItem * oldFocus,
Qt::FocusReason reason)
and also notice that you can check the connection's success/failure status via the bool return type of the QObject::connect method
So, in the end i found the answer to my own question. It was a mistake on my side.
in the connect() i used the slots without parenthesis/parameters. It should have looked like:
QObject::connect (scene,
SIGNAL(focusItemChanged(QGraphicsItem*,QGraphicsItem*,Qt::FocusReason)),
this,
SLOT(selectedItemChanged(QGraphicsItem*,QGraphicsItem*)));
I am trying to create pop-up menu depending on a variable as follows:
QMenu menu(widget);
for(int i = 1; i <= kmean.getK(); i++)
{
stringstream ss;
ss << i;
string str = ss.str();
string i_str = "Merge with " + str;
QString i_Qstr = QString::fromStdString(i_str);
menu.addAction(i_Qstr, this, SLOT(mergeWith1()));
}
menu.exec(position);
where:
kmean.get(K) returns an int value,
mergeWith1() is some `SLOT()` which works fine
Issue:
The loop creates an action on menu only for i=1 case, and ignores other values of i.
Additional information
When doing the same loop with casual int values (without convert) everything works fine. e.g. if I do in loop only menu.addAction(i, this, SLOT(...))) and my K=4, a menu will be created with four actions in it, named 1, 2, 3, 4 correspondingly.
What can be the problem caused by
I think the issue is in convert part, when I convert i to string using stringstream and after to QString. May be the value is somehow lost. I am not sure.
QESTION:
How to make the loop accept the convert part?
What do I do wrong in convert part?
In Qt code, you shouldn't be using std::stringstream or std::string. It's pointless.
You have a crashing bug by having the menu on the stack and giving it a parent. It'll be double-destructed.
Don't use the synchronous blocking methods like exec(). Show the menu asynchronously using popup().
In order to react to the actions, connect a slot to the menu's triggered(QAction*) signal. That way you can deal with arbitrary number of automatically generated actions.
You can use the Qt property system to mark actions with custom attributes. QAction is a QObject after all, with all the benefits. For example, you can store your index in an "index" property. It's a dynamic property, created on the fly.
Here's a complete example of how to do it.
main.cpp
#include <QApplication>
#include <QAction>
#include <QMenu>
#include <QDebug>
#include <QPushButton>
struct KMean {
int getK() const { return 3; }
};
class Widget : public QPushButton
{
Q_OBJECT
KMean kmean;
Q_SLOT void triggered(QAction* an) {
const QVariant index(an->property("index"));
if (!index.isValid()) return;
const int i = index.toInt();
setText(QString("Clicked %1").arg(i));
}
Q_SLOT void on_clicked() {
QMenu * menu = new QMenu();
int last = kmean.getK();
for(int i = 1; i <= last; i++)
{
QAction * action = new QAction(QString("Merge with %1").arg(i), menu);
action->setProperty("index", i);
menu->addAction(action);
}
connect(menu, SIGNAL(triggered(QAction*)), SLOT(triggered(QAction*)));
menu->popup(mapToGlobal(rect().bottomRight()));
}
public:
Widget(QWidget *parent = 0) : QPushButton("Show Menu ...", parent) {
connect(this, SIGNAL(clicked()), SLOT(on_clicked()));
}
};
int main (int argc, char **argv)
{
QApplication app(argc, argv);
Widget w;
w.show();
return app.exec();
}
#include "main.moc"
Today I encountered a problem with repaint() function from QT libraries. Long story short, I got a slot where I train my neural network using BP algorithm. I had tested the whole algorithm in console and then wanted to move it into GUI Application. Everything works fine except refreshing. Training of neural networks is a process containing a lot of computations, which are made in bp_alg function (training) and licz_mse function (counting a current error). Variable ilosc_epok can be set up to 1e10. Therefore the whole process may last even several hours. Thats why I wanted to display a current progress after each 100000 epochs (the last if contition). wyniki is an object of QTextEdit class used for displaying the progress. Unfortunately, repaint() doesnt work as intended. At the beginning it refreshes wyniki in GUI, but after some random time it stops working. When the external loop is finished, it refreshes once again showing all changes.
I tried to change frequency of refreshing, but sooner or later it always stops (unless the whole training process stops early enough because of satisfying the break condition). It looks like at some moment of time the application decides to stop refreshing because of too many computations. Imo it shouldnt happen. I was looking for a solution among older questions and managed to solve the problem when I used qApp->processEvents(QEventLoop::ExcludeUserInputEvents); instead of wyniki->repaint();. However, Im still curious why repaint() stops working just like that.
Below I paste a part of the code with the problematic part. Im using QT Creator 2.4.1 and QT Libraries 4.8.1 if it helps.
unsigned long int ile_epok;
double mse_w_epoce;
for (ile_epok=0; ile_epok<ilosc_epok; ile_epok++) { //external loop of training
mse_w_epoce = 0;
for (int i=0; i<zbior_uczacy_rozmiary[0]; i++) { //internal loop of training
alg_bp(zbior_uczacy[i], &zbior_uczacy[i][zbior_uczacy_rozmiary[1]]);
mse_w_epoce += licz_mse(&zbior_uczacy[i][zbior_uczacy_rozmiary[1]]);
}
//checking break condition
if (mse_w_epoce < warunek_stopu) {
wyniki->append("Zakończono uczenie po " + QString::number(ile_epok) + " epokach, osiągając MSE: " + QString::number(mse_w_epoce));
break;
}
//problematic part
if ((ile_epok+1)%(100000) == 0) {
wyniki->append("Uczenie w toku, po " + QString::number(ile_epok+1) + " epokach MSE wynosi: " + QString::number(mse_w_epoce));
wyniki->repaint();
}
}
You're blocking your GUI thread, so repaints will not work, it's just plainly bad design. You're never supposed to block the GUI thread.
If you insist on doing the work in the GUI thread, you must forcibly chop the work into small chunks and return to the main event loop after each chunk. Nested event loops are evil, so don't even think you'd want one. All this has a bad code smell, so stay away.
Alternatively, simply move your computation QObject to a worker thread and do the work there.
The code below demonstrates both techniques. It's easy to notice that the chopping-up-of-work requires to maintain loop state inside of the worker object, not merely locally in the loop. It's messier, the code smells bad, again - avoid it.
The code works under both Qt 4.8 and 5.1.
//main.cpp
#include <QApplication>
#include <QThread>
#include <QWidget>
#include <QBasicTimer>
#include <QElapsedTimer>
#include <QGridLayout>
#include <QPlainTextEdit>
#include <QPushButton>
class Helper : private QThread {
public:
using QThread::usleep;
};
class Trainer : public QObject {
Q_OBJECT
Q_PROPERTY(float stopMSE READ stopMSE WRITE setStopMSE)
float m_stopMSE;
int m_epochCounter;
QBasicTimer m_timer;
void timerEvent(QTimerEvent * ev);
public:
Trainer(QObject *parent = 0) : QObject(parent), m_stopMSE(1.0) {}
Q_SLOT void startTraining() {
m_epochCounter = 0;
m_timer.start(0, this);
}
Q_SLOT void moveToGUIThread() { moveToThread(qApp->thread()); }
Q_SIGNAL void hasNews(const QString &);
float stopMSE() const { return m_stopMSE; }
void setStopMSE(float m) { m_stopMSE = m; }
};
void Trainer::timerEvent(QTimerEvent * ev)
{
const int updateTime = 50; //ms
const int maxEpochs = 5000000;
if (ev->timerId() != m_timer.timerId()) return;
QElapsedTimer t;
t.start();
while (1) {
// do the work here
float currentMSE;
#if 0
for (int i=0; i<zbior_uczacy_rozmiary[0]; i++) { //internal loop of training
alg_bp(zbior_uczacy[i], &zbior_uczacy[i][zbior_uczacy_rozmiary[1]]);
currentMSE += licz_mse(&zbior_uczacy[i][zbior_uczacy_rozmiary[1]]);
}
#else
Helper::usleep(100); // pretend we're busy doing some work
currentMSE = 2E4/m_epochCounter;
#endif
// bail out if we're done
if (currentMSE <= m_stopMSE || m_epochCounter >= maxEpochs) {
QString s = QString::fromUtf8("Zakończono uczenie po %1 epokach, osiągając MSE: %2")
.arg(m_epochCounter).arg(currentMSE);
emit hasNews(s);
m_timer.stop();
break;
}
// send out periodic updates
// Note: QElapsedTimer::elapsed() may be expensive, so we don't call it all the time
if ((m_epochCounter % 128) == 1 && t.elapsed() > updateTime) {
QString s = QString::fromUtf8("Uczenie w toku, po %1 epokach MSE wynosi: %2")
.arg(m_epochCounter).arg(currentMSE);
emit hasNews(s);
// return to the event loop if we're in the GUI thread
if (QThread::currentThread() == qApp->thread()) break; else t.restart();
}
m_epochCounter++;
}
}
class Window : public QWidget {
Q_OBJECT
QPlainTextEdit *m_log;
QThread *m_worker;
Trainer *m_trainer;
Q_SIGNAL void startTraining();
Q_SLOT void showNews(const QString & s) { m_log->appendPlainText(s); }
Q_SLOT void on_startGUI_clicked() {
QMetaObject::invokeMethod(m_trainer, "moveToGUIThread");
emit startTraining();
}
Q_SLOT void on_startWorker_clicked() {
m_trainer->moveToThread(m_worker);
emit startTraining();
}
public:
Window(QWidget *parent = 0, Qt::WindowFlags f = 0) :
QWidget(parent, f), m_log(new QPlainTextEdit), m_worker(new QThread(this)), m_trainer(new Trainer)
{
QGridLayout * l = new QGridLayout(this);
QPushButton * btn;
btn = new QPushButton("Start in GUI Thread");
btn->setObjectName("startGUI");
l->addWidget(btn, 0, 0, 1, 1);
btn = new QPushButton("Start in Worker Thread");
btn->setObjectName("startWorker");
l->addWidget(btn, 0, 1, 1, 1);
l->addWidget(m_log, 1, 0, 1, 2);
connect(m_trainer, SIGNAL(hasNews(QString)), SLOT(showNews(QString)));
m_trainer->connect(this, SIGNAL(startTraining()), SLOT(startTraining()));
m_worker->start();
QMetaObject::connectSlotsByName(this);
}
~Window() {
m_worker->quit();
m_worker->wait();
delete m_trainer;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"
I'm trying to show a busy waiting bar when one function is executing, my problem is it stop moving once the function starts.
MyProgressDialog *progBar= new MyProgressDialog();
QProgressBar* bar = new QProgressBar(progBar);
bar->setRange(0, 0);
bar->setValue(0);
progBar->setBar(bar);
QString labeltext=QString("<qt> <center><big><b>%1</b></big></center> <br><b>%2</b><br> %3 <br><b>%4</b><br> %5</qt>")
.arg(progBar->labeltext)
.arg("File in :")
.arg(FileI)
.arg("File out :")
.arg(FileO);
progBar->label->setText(labeltext);
progBar->setValue(10);
progBar->show();
progBar->setValue(20);
Sleep(500);
progBar->setValue(50);
Sleep(500);
MyFunction(FileI,FileO,mode,key);
Sleep(500);
progBar->setValue(80);
Sleep(500);
progBar->setValue(100);
progBar->close();
delete bar;
delete progBar;
I warpped my function with a sleep and set value in purpose to let it moving but in vain, when I remove them MyProgressdialog didn't show its contents, am I need to lunch my function in a separate thread ?
I tried to use QFutureWatcher:
QFutureWatcher<void> futureWatcher;
QFuture<void> f1 = run(
MyFunction,
filePath,
file.absolutePath()+"/OUT_"+fileN,
1,
key
);
QObject::connect(&futureWatcher, SIGNAL(finished()), progBar, SLOT(reset()));
QObject::connect(progBar, SIGNAL(canceled()), &futureWatcher, SLOT(cancel()));
QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int,int)), progBar, SLOT(setRange(int,int)));
QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), progBar, SLOT(setValue(int)));
// Start the computation.
futureWatcher.setFuture(f1);
// Display the dialog and start the event loop.
progBar->exec();
futureWatcher.waitForFinished();
delete progBar;
It works fine and my bar is moving when I call MyFunction just one time (for one file) but the problem occurs when I call MyFunction more than one time (for many files successively): it works but I get the same OUT_file for all files treated, I think it is multithreading issue.
EDIT: class MyProgressDialog
class MyProgressDialog: public QProgressDialog
{
Q_OBJECT
public:
MyProgressDialog()
{
qDebug()<<"MyProgressDialog constructor";
label=new QLabel(this);
QPalette* palette = new QPalette();
palette->setColor(QPalette::Window,"#F8F8FF");
setPalette(*palette);
QFont* font = new QFont("Courier New");
font->setItalic(true);
font->setPixelSize(15);
setFont(*font);
adjustSize();
setWindowIcon(QIcon(QApplication::applicationDirPath()+"/icons/icon1.png"));
setWindowFlags(Qt::WindowStaysOnTopHint);
setMinimumWidth(500);
setMinimumHeight(200);
labeltext=QString("Please wait until Encryption/Decryption was done");
label->setText(labeltext);
label->adjustSize();
label->setWordWrap (true);
setLabel(label);
setRange(0,100);
setWindowTitle("MyFunction progress");
setModal(true);
}
~MyProgressDialog()
{
qDebug()<<"MyProgressDialog destructor";
delete label;
}
public:
int value;
QString labeltext;
QLabel* label;
};
UI in Qt is event driven. So executing your code in same thread as ui will block every ui event untill your function is finished. There are two aproaches to show progress.
Use thread for computing and send update events to UI
Easier way: after each setValue and show calls call QApplication::processEvents(); static method. Calling QApplication::processEvents() will dispatch events currently queued on event loop. Those events include all ui related events
Here is code sample for gcc/mingw gcc
#include <QApplication>
#include <QProgressBar>
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
QProgressBar bar;
bar.setRange(0, 100);
bar.show();
app.processEvents();
usleep(250000);
for(int i = 1; i <= 10; ++i)
{
bar.setValue(i * 10);
app.processEvents();
usleep(250000);
}
return 0;
}
It shows progress bar and steps it by 10 every 0,25s
Your code should look something like this:
MyProgressDialog *progBar= new MyProgressDialog();
QProgressBar* bar = new QProgressBar(progBar);
bar->setRange(0, 100); // note your "busy state won't be shown as you're changing value right after show
bar->setValue(0);
progBar->setBar(bar);
QString labeltext=QString("<qt> <center><big><b>%1</b></big></center> <br><b>%2</b><br> %3 <br><b>%4</b><br> %5</qt>")
.arg(progBar->labeltext)
.arg("File in :")
.arg(FileI)
.arg("File out :")
.arg(FileO);
progBar->label->setText(labeltext);
progBar->setValue(10);
progBar->show();
QApplication::processEvents(); // HERE
progBar->setValue(20);
QApplication::processEvents(); // HERE
Sleep(500);
progBar->setValue(50);
QApplication::processEvents(); // HERE
Sleep(500);
MyFunction(FileI,FileO,mode,key);
Sleep(500);
progBar->setValue(80);
QApplication::processEvents(); // HERE
Sleep(500);
progBar->setValue(100);
progBar->close();
QApplication::processEvents(); // HERE
delete bar;
delete progBar;