tags:

views:

181

answers:

1

I am porting an application from QT3 to QT4, and keep running into problems when a thread is updating a QProgressDialog. The original code was roughly designed like so:

class ScanProcess : QObject{
Q_OBJECT
public:
  QProgressDialog* progress;
private:
  ScanProcessThread* thread;
};

class ScanProcessThread : QThread {
Q_OBJECT
public:
  void run();
};

This is after running qt3to4 and making the appropriate changes from the QT Porting guide.

In the original design, inside the ScanProcessThread:

void ScanProcessThread::run(){
//...
ProgressInfo *prog = new ProgressInfo(); //then fill it in
QCustomEvent* progEvent = new QCustomEvent(QEvent::User+1, (void*)prog);
QCoreApplication::postEvent(parent, progEvent);//Parent is pointer to the ScanProcess
//...
}

void ScanProcess::customEvent(QCustomEvent *e){
  if(e->type() == QEvent::User+1){
    //update QProgressDialog
    progres->setValue(prog.index);//Value from the ProgressInfo passed above
    //This line crashes deep in ntdll, but I have traced it to the QProgressDialog::repaint()
  }
}

struct ProgressInfo {int count; int index; QString text;};

So, that's the important code. The call to QProgressDialog::Repaint seems to always crash somewhere deep in ntdll. I have tried two other methods: 1) Use QCoreApplication::postEvent() 2) Pass the QProgressDialog* and let ScanProcessThread update it directly. In every case, it's the QProgressDialog::repaint() that fails. Any ideas?

(qt4.4, windows xp sp3, Visual Studio 2008/)

A: 

Since only the main thread can access the GUI, you have to be sure that you're handling the ScanProcess::customEvent() routine in the main thread. Usually the easiest way is to make sure that any thread that emits or handles signals have it's own event loop.

Javier
I agree, the crash makes me think that the ScanProcess class isn't instantiated in the main thread, but in some other thread.
Caleb Huitt - cjhuitt
Why does QT require GUI updates to happen in the main thread?
David Souther
@David Souther: the GUI routines aren't thread-safe. it's very hard to do, given that in most OS the GUI calls have a lot of hidden local state indexed 'per process' instead of using some finer granularity, making the whole GUI API non thread-safe
Javier
Fair enough. I come from a Java background, which doesn't impose those restrictions, and yes, I've seen foot-shots from misusing Java GUI classes that way :)
David Souther
Working with it a bit more, I am able to use QProgressDialog::setLabelText() with no problems. Also, @Javier, you mention ensuring that signal emitting and handling threads have "their own event loop" - what do you mean by this?
David Souther
(edit: added a link to http://doc.qt.nokia.com/4.6/threads-qobject.html#per-thread-event-loop)
Javier