PDA

View Full Version : QDialog does not appear until calculations are finished



Richard H
15th March 2017, 17:44
Hi, I have a problem with the GUI for a laser beam propagation simulation I am currently writing with C++ and QT. The simulation itself works, but I implemented a dialog which should actually update a plot, using QCustomPlot and a progressBar. Unfortunately, the QDialog only appears after all the calculations are done, showing the plot of the final result and a progress bar at 100%.

Is there any way to make sure my dialog is actually visible during the calculations?

Here is how I create the dialog, after the preceding information has been processed:


void bpmSettings::runBPM()
{
//...
bpmdialog *b = new bpmdialog;
b->show();
this->close();
}

Here is the header of the dialog:


#ifndef BPMDIALOG_H
#define BPMDIALOG_H

#include <QDialog>
#include "vector2d.h" // a vector class I wrote which the simulation is based on

extern GaussData globalData;

namespace Ui {
class bpmdialog;
}

class bpmdialog : public QDialog
{
Q_OBJECT

public:
explicit bpmdialog(QWidget *parent = 0);
~bpmdialog();

private:
Ui::bpmdialog *ui;
void envPlot(const vector2d<double>& field); // plots the vector2d field by using the QCustomPlot widget in the ui.
void bpm(); // starts simulation
};

#endif // BPMDIALOG_H

And this is how my implementation of the dialog looks like:


bpmdialog::bpmdialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::bpmdialog)
{
ui->setupUi(this);
bpm();
}

I hope I provided enough information. The bpm() method is basically a for loop calculating a new 2d field in every iteration, by using a Gauss Seidel algorithm to solve a linear system. The 2d field is then plotted with the envPlot(field) method in every iteration.

Thank you very much in advance for your help!
Best regards,
Richard

Lesiok
15th March 2017, 18:08
1. Define bpm as slot.
2. bpm should calculate only one 2d field.
3. The skeleton should look like :
bpmdialog::bpmdialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::bpmdialog)
{
ui->setupUi(this);
QTimer::singleShot(0,SLOT(bpm()));
}

bpmdialog::bpm()
{
//calculate one 2d field
envPlot(field);
QTimer::singleShot(0,SLOT(bpm()));
}

Richard H
15th March 2017, 18:33
Thanks a lot for the quick answer! I just tried calling my bpm() method the way you described without changing it, I think that might already solve the problem, at least for the first plot. Now QTimer::singleShot() takes three arguments, could you please explain what the second argument *receiver means and what I should put there?

In the documentation it looks like this:
void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)

http://doc.qt.io/qt-5/qtimer.html#singleShot

Thank you!

EDIT: ok sorry, that was a dumb question. I figured it out. It should be QTimer::singleShot(0, this, SLOT(bpm())). Thanks again!

anda_skoa
16th March 2017, 13:24
Just to add some background info:

you didn't see the dialog because you called the long operation in the dialog's contructor.
So your code didn't reach the show() before it was completed.

By delaying its invocation with the timer you not only make the dialog constructor finish right aways and letting the main code show it, you also allow the dialog to actually process the show event that is triggered by show().

I.e. GUI systems such as QtWidgets are highly event driven, letting the main thread, which handles the events for the UI, run long operations results in UI not updating.
Hence Lesiok's suggestion to let bpm() ideally only calculate a subset and continuously trigger further calculations via the delay mechanism again.

This allows the main thread to catch up with UI events between these delayed calls.

Cheers,
_