PDA

View Full Version : update a wigdet in a thread is no allow?



lanmanck
21st October 2009, 16:33
hi,guys:
i receive some picture data from internet,and now want to display in a widget with my form.(ON RED HAT ENTERPRISE Linux 5.0)
the "widget" is inherited from QWidget, and use these code to attatch to the mainform:

ui->widget->setVisible(0); //a Widget to provide geometry
//define as : class WidgetVideoArea : public QWidget

videoarea = new WidgetVideoArea(this);
videoarea->setGeometry(ui->widget->geometry());
videoarea->show();

then ,i recevie data from thread1,and emit a signal to mainwindow,so the picture can update.


void MainWindow::updateVideo(QByteArray videobufs)
{
const char *data = videobufs.constData();
QImage smage((uchar*)data,240,320,QImage::Format_RGB16);
videoarea->setRepaintFlag(smage);
videoarea->repaint();
}
now it works.
But i think that will freeze GUI. so i create another thread,thread2, to update the picture separately.
the function updateVideo(QByteArray videobufs) above is set to "public",so i can use it in thread2.
However,when i do that, application output:

X Error: BadDrawable (invalid Pixmap or Window parameter) 9
Major opcode: 62 (X_CopyArea)
Resource id: 0x0
QPixmap: It is not safe to use pixmaps outside the GUI thread
...............
so how can i update the widget in a thread? will these appear in embedded board?(i will port to ARM later).
i used this method in VisualC++ before, and had no problem.
thanks.

caduel
21st October 2009, 16:50
correct: you may only use QWidgets from the main aka gui thread.

you may produce a QImage in another thread, though. pass it to the main thread (eg using signal/slot, which is thread safe) and paint it there.

HTH

lanmanck
22nd October 2009, 03:11
hi:


you may produce a QImage in another thread, though. pass it to the main thread (eg using signal/slot, which is thread safe) and paint it there.

==>>that's what i have done :)
SO, can i only pass a QImage to main thread through another thread?
if the picture is recevied quickly(eg, 30fps), in the gui main thread, will the window be slower or look like freeze?
BTW,is there a double buffer(like VisualC++ MFC) concept in QT?

lanmanck
23rd October 2009, 10:18
hello?..............

spud
23rd October 2009, 14:11
Double buffering is enabled by default in Qt. (http://doc.trolltech.com/4.1/qwidget.html#transparency-and-double-buffering)

btw

For rapidly updating custom widgets that constantly paint over their entire areas with opaque content, such as video streaming widgets, it is better to set the widget's Qt::WA_OpaquePaintEvent, avoiding any unnecessary overhead associated with repainting the widget's background.

I you call QWidget::update() instead of QWidget::repaint(), your window will stay responsive, but some frames might not be drawn.

lanmanck
24th October 2009, 07:19
thanks.
could you show me how to use the update() member function(to paint a QImage to my custom widget area)?
it seems like no examples available....
now i use this method:


void WidgetVideoArea::paintEvent(QPaintEvent*pPaintEven t)
{
if(repaintme)
{
target.setX(0);
target.setY(0);
target.setWidth(width());
target.setHeight(height());

painter.begin(this);
painter.drawImage(target,image);
painter.end();

repaintme = false;
}
}

caduel
24th October 2009, 09:19
update() schedules a repaint-Event. Qt will repaint your widget when it has the time and when it is necessay.

If your image is large, you might want to consider QPaintEvent::rect().
This repaintme stuff should not be necessary. What do you use it for?
(A repaint could be scheduled, because another window obscured your widget. Yes, with buffering maybe not, but it could.)

spud
24th October 2009, 13:33
void WidgetVideoArea::newImage(const QImage& image)//slot
{
this->image = image;
update();
}

void WidgetVideoArea::paintEvent(QPaintEvent*pPaintEven t)
{
QPainter painter(this);
painter.drawImage(image, ...);
}

lanmanck
25th October 2009, 04:05
yes ,i use update() to replace repaint() ,and found it worked.
BTW,the "repaintme" stuff is used in my old project :),and i removed it now.
thanks everyone .