2009-12-23 68 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