2009-12-23 35 views
1

我有一个应用程序,它有一个进度条&产生一个工作线程做一些工作&报告返回进度。对话框类重写了customEvent方法,以便我可以处理通过工作线程传递给gui线程的事件。在我使用QThread派生类作为工作者线程之前,我将它改为使用ACE_Thread_Manager-> spawn()以及工作者的静态函数。在QT4中使用自定义事件

当我运行该应用程序并按下按钮时,问题就会显示出来,因此工作人员开始生成&开始工作。当它发送信号来递增进度条时,我得到以下错误记录到标准输出。

的QPixmap:这是不是安全使用GUI线程

这似乎当progressBar->的setValue()被调用发生之外的像素映射。所以看起来进度条的设置发生在与主gui线程不同的线程中。我不清楚这是可能的。我的印象是,我有一个主要的gui线程,它有我的gui & customEvent方法在同一个线程上,而worker在它自己的线程上。这个假设是错误的吗?使用QThread派生类与静态run_svc方法有什么不同吗?

任何帮助,将不胜感激。 customEvent处理程序,run_svc和按钮处理程序代码的代码片段位于下方,代码已附加。

void MyDlgEx::customEvent(QEvent * e) 
{ 
    if (e->type() == IdNumOperations) 
    { 
     NumOperations* pEvt = static_cast<NumOperations*>(e); 
     _steps = 0; 
     cout << "Num Operations = " << pEvt->operations() << endl; 
    } 
    else if (e->type() == IdStep) 
    { 
     if (_steps % 10 == 0) 
     { 
      cout << "Step++ = " << _steps << endl; 
     } 

     _steps++; 
     _progressBar->setValue(_steps); 
    } 
} 

void* MyDlgEx::run_svc(void* args) 
{ 
    auto_ptr<ThreadArgs> thread_args(static_cast<ThreadArgs*>(args)); 
    QApplication::sendEvent((QObject*)thread_args->m_pDlg, new NumOperations(300)); 

    // does some work that takes time -- ommitted for clarity 
    // called in a loop 
    QApplication::sendEvent((QObject*)thread_args->m_pDlg, new Step()); 

    QApplication::sendEvent((QObject*)thread_args->m_pDlg, new Completed()); 

    return 0; 
} 

按钮处理 注释掉其中其中I用于从QThread的派生的QT班线。使用ACE必须产生线程才能发现此问题。

void MyDlgEx::btnShowProgress_clicked() 
{ 
    //_pProc = new ProcessThread(this); 
    //_pProc->run(); 

    auto_ptr<ThreadArgs> thread_args(new ThreadArgs(this)); 
    if (ACE_Thread_Manager::instance()->spawn(
       MyDlgEx::run_svc, 
       static_cast<void*>(thread_args.get()), 
       THR_DETACHED | THR_SCOPE_SYSTEM) == -1) 
     cout << "Failed to spawn thread." << endl; 

    thread_args.release(); 
} 

回答

4

尝试调用QApplication :: postEvent(...)而不是QApplication :: sendEvent()。文档说sendEvent直接发送事件,意味着它直接从另一个线程调用customEvent()函数。 postEvent()将事件添加到事件队列中,稍后可以通过主GUI事件循环将其分派给customEvent()。

仅仅因为customEvent()函数是在主GUI线程中创建的对象的成员,并不意味着其他线程无法调用该函数。我相信当你从另一个线程调用QApplication :: sendEvent()时会发生什么。

+0

是的,更改为postEvent工作。我将不得不做一些更多的测试,并打印出线程ID以便更好地理解发生了什么。我习惯了SendMessage&PostMessage在WIN32 api中的SendMessage等待,直到处理程序完成,因为PostMessage只是发送消息并返回。 WIN32 Post&Send消息是否与QT相同或略有不同? 感谢您的回复。这是一个不错的圣诞礼物:) – 2009-12-25 17:13:25

+0

我不熟悉WIN32 API,但对我来说听起来是一样的。 sendEvent块,因为它直接调用事件处理程序,但在将事件推入队列后postEvent将返回,并且如果从GUI线程调用postEvent,则该事件稍后将由另一个线程或同一个线程处理。我怀疑(但不知道)Qt和WIN32版本之间存在细微的差异,但是它听起来像是它们在主要观点上是相似的。 你看过使用Qt信号和插槽而不是自定义事件吗?他们可能会让事情变得更简单,更清洁。 – 2009-12-26 16:37:55