Qwt: Is it possible to perform GUI operations from a separate QProcess?
First of all, I am thinking the answer is no, but I cannot say for sure, so a confirmation would be nice.
I am new to Qt and Qwt (and GUI programming in general), and I am relatively new to C++.
I know you should not perform any GUI operations from a separate thread, but I was wondering if I could make something work using QProcess (or fork() obviously) and QSharedMemory, while still making it "feel" like one application.
My goal is to build a GUI to display large amounts of data in real-time with Qt and Qwt. The GUI needs to contain 2 plots: the first plot needs to replot a completely new set of 1e6 samples for every update (needs to be done very quickly, minimum 10FPS), the second plot is a waterfall display (Google "fft waterfall display" if unfamiliar) based on the data of the first plot. My biggest concern is the speed of painting.
If I only create the first plot, my GUI updates at about 17FPS.
I am running my program on CentOS 7 with Qt 5.9.7 and Qwt 6.1.5.
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
The restriction on multithreaded GUI operations is that GUI operations that paint to the screen must occur in the main thread. You can paint to QImage bitmaps from any thread and transfer them to the GUI thread for on-screen rendering. So in your case, if you can calculate and generate either or both of your images in separate threads, your main GUI thread only has to display them and that can be easily done at 10 fps.
I am not sure where the actual QImage bits have to live - ie. whether the QImage has to be allocated in the main thread or whether it can be allocated in the thread that fills it. In any case, you should not perform your screen updates based on some QTimer or similar mechanism that establishes an update rate. Instead, you should use Qt's signal and slot mechanism to let the image creation thread tell the main thread that a new image is ready and to update the on-screen display. Otherwise, you run the risk of either wasting a lot of time in inappropriate polling or seeing glitches due to incompletely rendered images.
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
Originally Posted by
seanj
I am running my program on CentOS 7 with Qt 5.9.7 and Qwt 6.1.5.
Better use Qwt 6.2 from SVN ( being released soon ) as it has a significant optimization ( QwtPlotCurve::FilterPointsAggressive ), that might be relevant for your usecase.
Uwe
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
Originally Posted by
d_stranz
In any case, you should not perform your screen updates based on some QTimer or similar mechanism that establishes an update rate. Instead, you should use Qt's signal and slot mechanism to let the image creation thread tell the main thread that a new image is ready and to update the on-screen display. Otherwise, you run the risk of either wasting a lot of time in inappropriate polling or seeing glitches due to incompletely rendered images.
Currently, my first plot paints onto a widget still, but I plan on modifying my code to paint onto a QImage in a separate thread later on. Before I do that though, I am just curious, how could I use the signal and slot mechanism to notify when I am finished painting? Would I need to re-implement paintEvent and emit a signal after calling painter.end() ?
Thank you, I greatly appreciate your help.
Added after 4 minutes:
Quote:
Originally Posted by
Uwe
Better use Qwt 6.2 from SVN ( being released soon ) as it has a significant optimization ( QwtPlotCurve::FilterPointsAggressive ), that might be relevant for your usecase.
Uwe
Awesome! Thanks for the reply. I will check it out soon.
How does this compare with QwtPlotCurve::FilterPoints? When I set QwtPlotCurve::FilterPoints to true, my frame rate drops from 16.5 FPS to 14.5 FPS.
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
how could I use the signal and slot mechanism to notify when I am finished painting?
You're probably not going to have an actual paintEvent() in your thread, but instead you will have some other method that creates a new QImage with the current data. For whatever class it is that implements this updating, be sure it is derived from QObject (so it can emit signals), and implement a signal with a signature something like:
Code:
signals:
void imageUpdated
( const QImage & image
);
In the GUI thread, add a slot to whatever QWidget class will display the image, and connect that slot to the thread's signal:
Code:
public slots:
void onImageUpdated
( const QImage & image
);
In that slot, copy the image, then call QWidget::update() to schedule a paintEvent().
I am not familiar enough with the current state of Qwt to know how you would integrate this QImage-based rendering into a QwtPlot. Perhaps you would need to actually paint the entire QwtPlot into the QImage in your thread, or perhaps Qwt has a spectrogram-like plot where a QImage can be substituted for a calculated spectrogram.
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
Originally Posted by
seanj
How does this compare with QwtPlotCurve::FilterPoints?
FilterPointsAggressive limits the maximum number of lines to be painted to: 4 * canvas.width() ( or height - depending on the orientation ).
So if you have a line plot where the samples are ordered in x or y direction the effect will be very significant for 1e6 samples.
If you have a scatter plot you could try what is done in the scatterplot example.
HTH,
Uwe
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
Originally Posted by
d_stranz
You're probably not going to have an actual paintEvent() in your thread, but instead you will have some other method that creates a new QImage with the current data. For whatever class it is that implements this updating, be sure it is derived from QObject (so it can emit signals), and implement a signal with a signature something like:
Code:
signals:
void imageUpdated
( const QImage & image
);
In the GUI thread, add a slot to whatever QWidget class will display the image, and connect that slot to the thread's signal:
Code:
public slots:
void onImageUpdated
( const QImage & image
);
In that slot, copy the image, then call
QWidget::update() to schedule a paintEvent().
Is it possible to implement similar functionality using the slot and signal mechanism if I am painting onto a widget, not a QImage? I attempted to do so, but when I run the program, no data is ever displayed on the plot.
In plot constructor:
Code:
connect(this, SIGNAL(plotUpdated()), this, SLOT(onPlotUpdated()));
d_timer->singleShot(10000, this, SLOT(onTimerFinished()));
onTimerFinished() slot, (added single shot timer and created this because I read that signals should be emitted inside an event):
Code:
void Plot::onTimerFinished()
{
replot();
Q_EMIT plotUpdated();
}
onPlotUpdated() slot:
Code:
void Plot::onPlotUpdated()
{
if (index < 10)
{
// update d_curve's data
d_curve->updateSamples(index);
replot();
index += 1;
frame += 1;
// if index is 10, set to 0 to continue plotting
if (index == 10) index = 0;
// stop the plotting
if (frame > 1000)
{
// set index to 11 to stop plotting
index = 11;
}
}
Q_EMIT plotUpdated();
}
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
I read that signals should be emitted inside an event
Don't know where you read this, but it is wrong. Signals can be emitted from any method. How they get handled depends on what type of signal/slot connection was made. See the documentation for QObject::connect().
Quote:
onPlotUpdated() slot:
You realize you have set up an infinite loop here, right? You have connected the plotUpdated() signal to the onPlotUpdated() slot, and in that slot you emit the plotUpdated() signal, which calls the slot, which emits the signal, which calls the slot...
Quote:
d_timer->singleShot(10000, this, SLOT(onTimerFinished()));
I don't have any idea what you are trying to do with this QTimer. And if all you want to do is call the onPlotUpdated slot, then make that the slot connected to the timer's timeout signal. No need to add a special slot that simply emits the plotUpdated signal.
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
Originally Posted by
d_stranz
Don't know where you read this, but it is wrong. Signals can be emitted from any method. How they get handled depends on what type of signal/slot connection was made. See the documentation for
QObject::connect().
You realize you have set up an infinite loop here, right? You have connected the plotUpdated() signal to the onPlotUpdated() slot, and in that slot you emit the plotUpdated() signal, which calls the slot, which emits the signal, which calls the slot...
I don't have any idea what you are trying to do with this QTimer. And if all you want to do is call the onPlotUpdated slot, then make that the slot connected to the timer's timeout signal. No need to add a special slot that simply emits the plotUpdated signal.
1. I do not remember exactly, but I thought I read it in a Qt forum, I cannot find it anymore.
2. I am aware of the infinite loop, my plan was to just add a counter variable and only emit the signal when the count is below a certain value.
3. The sole reason I used a single shot timer is just so I could enter the event loop to emit a signal, but I now know that is not necessary.
Thank you very much for the guidance, I really appreciate it.
Re: Qwt: Is it possible to perform GUI operations from a separate QProcess?
Quote:
Signals can be emitted from any method.
A small correction - the method has to be a member of a class derived from QObject that contains the Q_OBJECT macro in its class definition, and the signal function itself must be declared as a signal in that class. Otherwise the MOC compiler won't generate the boilerplate code that defines the signal and integrates it into signal / slot connections. Typically signals are private or protected class methods that can't be called except from within their own classes.