[Qt-interest] Problem drawning in the GUI Thread with Data from another Thread

Malyushytsky, Alex alex at wai.com
Fri Jul 3 02:06:21 CEST 2009


I am not sure I correctly followed your design.
I assume graphUpdate is called  from the working thread (through signal slot mechanics or directly).
In this case you have to make sure graphUpdate is not running when painter2.drawImage(QPoint(0,0), *buffer);
is executed.
Otherwise for example buffer may be deleted when drawImage is still drawing. This means application crash or termination (well exception handling would be great any way).

QMutex or other thread safety mechanics can be a friend here.

The simplest approach would be to lock  paintEvent and graphUpdate with mutex, but I would suggest to add some code make them actually run simultaneously, in order to allow graphUpdate to draw into its buffer while Widget is painting.

In this case 2 buffers are required. One buffer is used to draw from the paintEvent. Another buffer is used by graphUpdate to draw into.

Widget itself paints from the buffer any time it needs an update (no matter who caused the update).
graphUpdate is always drawing into second buffer, but when it finish drawing and the image is ready to be shown, it swaps the buffers (it means just changing pointers) and then forces Widget update (through thread safe procedures, like Queued connection).

You still will need to guard the pointers when swapping them and in the paintEvent, but this operations is very fast.

Hope this helps,
     Alex







From: qt-interest-bounces at trolltech.com [mailto:qt-interest-bounces at trolltech.com] On Behalf Of O Caldas
Sent: Thursday, July 02, 2009 4:33 PM
To: qt-interest at trolltech.com
Subject: Re: [Qt-interest] Problem drawning in the GUI Thread with Data from another Thread

oh, and here is the code of the paintEvent() method:

void PopGraph::paintEvent(QPaintEvent*){
    QPainter painter2(this);
    painter2.drawImage(QPoint(0,0), *buffer);

}

buffer is an atribute QImage* of the class
2009/7/2 O Caldas <caldaz.sheep at gmail.com>
hi, my application draws a horizontal graphics of the data generated by the
thread. it uses vectors that are directly modified by the worker thread. ive
tryed to send the vectors in the signal but it stays the same.

here is the code that create the image that will be draw :

void PopGraph::graphUpdate(){
    delete(buffer);
    buffer = new QImage(size(), QImage::Format_ARGB32);
    QSize d = size();
    long long nMax = (int)ceil(log10(_d->getPopulationMax()));
    double yscale = d.height()/(double)nMax;
    int tickscale = 1;

    // draw horizontal tick marks
    Qt::PenStyle style = Qt::PenStyle(Qt::SolidPattern);
    Qt::PenCapStyle cap = Qt::PenCapStyle(Qt::FlatCap);
    Qt::PenJoinStyle join = Qt::PenJoinStyle(Qt::MiterJoin);
    QPainter painter(buffer);
    painter.fillRect(rect(), Qt::white);

    painter.setPen(QPen(Qt::black, 1, style ,cap,join));
    for (int i=0; i<=nMax; i++) {
        int y = size().height()-(int)(i*yscale);
        painter.drawLine(0, y, d.width(), y);
        char st[6] = "10^";
        strcat(st, intToStr(i));
        painter.drawText(0, y, QString(st));//("10^" + String.valueOf(i), 0, y);
    }
    // draw vertical (date) tick marks
    long long lastday = -1;
    vector<long long> hours = _d->getPopulationHours();
    int end = d.width();
    if (hours.size()<d.width())
        end = hours.size();
    for (int i=0; i<end; i++) {
        if (lastday != hours[hours.size()-i-1]/24) {
            lastday = hours[hours.size()-i-1]/24;
            painter.drawLine(d.width()-i, 0, d.width()-i, d.height());
            painter.drawText(d.width()-i+1, 11, QString( intToStr(lastday+1)));
        }
    }
    // draw antigen level curves
    vector<Antigen*>* pops = _d->getAntigens();
    vector<QColor> popcolors = _d->getAntigenColors();
    int s = _d->getAntigenLevels().size();

    for (int j=0; j<s; j++) {
        painter.setPen(popcolors[j]);
        // draw legend
        painter.drawText(0, painter.fontMetrics().ascent()*(j+1),QString(pops->at(j)->getName()->data()));

        // draw curves
        vector< long long > data = _d->getAntigenLevels()[j];
        end = d.width();
        if (data.size()<(unsigned )d.width())
            end = data.size();
        for (int i=0; i<end; i+=2)  // just plot every other hour
            if (data[data.size()-i-1]>0){

                painter.drawRect(d.width()-i-1,
                        d.height()-1-(int)
                        (log10(data[data.size()-i-1])*yscale),
                        2,
                        2);
            }
    }
    // draw T cell level curves
    s = _d->getTCellColors().size();
    for (int j=0; j<s; j++) {
        painter.setPen(_d->getTCellColors()[j]);
        // draw legend
        if (_d->getTCells()->size()<10)
            painter.drawText(0, painter.fontMetrics().ascent()*(j+1+(_d->getAntigens()->size())), QString(_d->getTCells()->at(j)->getName()->data()));
        // draw curves
        vector<long long> data = _d->getTCellLevels()[j];
        end = d.width();
        if (data.size()<(unsigned )d.width()) end = data.size();
        for (int i=0; i<end-1; i++){
            if ((data[data.size()-i-1]>0) && (data[data.size()-i-2]>0)){
                painter.drawLine(d.width()-i-1,
                        d.height()-(int)
                        (log10(data[data.size()-i-2])*yscale),
                        d.width()-i,
                        d.height()-(int)
                        (log10(data[data.size()-i-1])*yscale));

            }
        }

    }
//    if(contador == 1){
//        contador =0;
        update();

//    }

}

thanks for your help!
2009/7/2 Sean Harmer <sean.harmer at maps-technology.com>

On Thursday 02 Jul 2009 06:27:05 O Caldas wrote:
> Hi, im working on a project where I have two threads, one Worker thread,
> that do some calculations,
> and one GUI Thread, that draw some graphics in a QWidget.
>
> The Worker thread is a class that inherits from QThread, and the GUI Thread
> is the main thread obviously.
>
> Im geting the worker thread to send a signal every end of calculation step,
> and connecting this signal
> to the method that draws the graphic in the GUI Thread
>
> like this:
>
> connect(calculator, SIGNAL(calculated(),this,
>             SLOT(updateView()));
>
> The problem is, when the calculation gets to fast, the GUI thread just bugs
> and the program terminates.
> It seems that the calculator thread starts sending too much signals and the
> GUI thread cant handle it,
> or something like this.
>
> i've tryed to use Qt::BlockingQueuedConnection but it is too slow.
>
> if someone knows what im doing wrong, or the right way to build a program
> like that please help!
It sounds like you are taking the right general approach. What does your app
have to do in order to visualise the results? How do you get the data to the
main thread as I notice your signal does not marshall any data across to it?

If the visualisation in the main thread really is very expensive to perform
then maybe you should only visualise every n'th frame. You could maybe make
this an option that the user can set depending upon the performance of their
graphics subsystem.

Sounds like you have identified the bottle neck in your app. If you provide
some more information we might be able to help you improve it.

Cheers,

Sean

_______________________________________________
Qt-interest mailing list
Qt-interest at trolltech.com
http://lists.trolltech.com/mailman/listinfo/qt-interest



--
Daniel Mendes Caldas



--
Daniel Mendes Caldas


---------------------------------------------------------------------------------------------------
Weidlinger Associates, Inc. made the following annotations.

"This message and any attachments are solely for the intended recipient and may contain confidential or privileged information. If you are not the intended recipient, any disclosure, copying, use, or distribution of the information included in this message and any attachments is prohibited. If you have received this communication in error, please notify us by reply e-mail and immediately and permanently delete this message and any attachments. Thank you."

"Please consider our environment before printing this email."




More information about the Qt-interest-old mailing list