将线程从QT3移植到QT4

将线程从QT3移植到QT4,qt,qt4,Qt,Qt4,我正在将一个应用程序从QT3移植到QT4,并且在线程更新QProgressDialog时一直遇到问题。原始代码大致设计如下: class ScanProcess : QObject{ Q_OBJECT public: QProgressDialog* progress; private: ScanProcessThread* thread; }; class ScanProcessThread : QThread { Q_OBJECT public: void run(); };

我正在将一个应用程序从QT3移植到QT4,并且在线程更新QProgressDialog时一直遇到问题。原始代码大致设计如下:

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

class ScanProcessThread : QThread {
Q_OBJECT
public:
  void run();
};
这是在运行qt3to4并从QT移植指南中进行适当更改之后进行的

在原始设计中,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;};
这就是重要的代码。对QProgressDialog::Repaint的调用似乎总是在ntdll深处的某个地方崩溃。我尝试了另外两种方法: 1使用QCoreApplication::postEvent 2传递QProgressDialog*并让ScanProcessThread直接更新它。在任何情况下,失败的都是QProgressDialog::repaint。有什么想法吗


qt4.4、windows xp sp3、Visual Studio 2008/

由于只有主线程可以访问GUI,因此必须确保您正在主线程中处理ScanProcess::customEvent例程。通常最简单的方法是确保任何发出或处理信号的线程都有它。

我同意,崩溃让我认为ScanProcess类不是在主线程中实例化的,而是在其他线程中实例化的。为什么QT要求在主线程中进行GUI更新?@David Souther:GUI例程不是线程安全的。这很难做到,因为在大多数操作系统中,GUI调用都有很多隐藏的本地状态索引“每个进程”,而不是使用更精细的粒度,这使得整个GUI API不具有线程安全性。我来自Java背景,没有强加这些限制,是的,我看到过错误使用Java GUI类的例子:使用它多一点,我就能毫无问题地使用QProgressDialog::setLabelText。另外,@Javier,您提到确保信号发送和处理线程有自己的事件循环-这是什么意思?只是一个注释,但我会创建自己的自定义事件类来传递进度信息,而不是强制执行作废和返回。如果要发布到的对象没有删除指针,而您发布的代码没有删除指针,则可能存在内存泄漏。此外,如果发布到的类在处理事件之前消失,或者如果派生类重写它并忘记这样做,或者…@cjhuitt如果我自己编写应用程序,我会做很多不同的事情:也就是说,这段代码确实负责清理customEvent中自己的指针,我忘了添加那一行。