2012-04-06 12 views
1

問題是關於將現有的基於pthread的基於C,pthread的應用程序與QT GUI進行接口。這似乎是一個簡單的任務,但是,當我搜索(在互聯網上和通過試驗&錯誤),我沒有找到一個可接受的解決方案。將數據和事件從pthread發送到QT QApplication使用QLabel和QImage

現在,該應用程序大量使用了預先存在的C庫,我無法修改其代碼。

基本上,預先存在的庫實現了一個循環,它以週期性的方式調用一些函數(使用一些數據)。只有那些我能夠定義的函數(函數指針)。

在一個完整的應用中,預先存在的庫環以下述方式調用這些函數(又名「初始化」,「過程」和「UNINIT」):

init(f); 
process(f); 
process(f); 
... 
process(f); 
... 
process(f); 
uninit(f); 

的「f」爲一個結構,允許保持調用呼叫的相關數據,「init」和「uninint」函數用於設置和銷燬由f分配的數據。

現在,process()函數進行了一些計算,最後的結果是一個矩陣,我想在QT GUI中以圖像的形式顯示它(就像它獲得的那樣)。

但是,QT GUI有自己的阻塞事件循環,又名myApp.exec()。因此,爲了達到這個目的,我在我的「init」函數中創建了一個新線程(pthread),它將首先用相關數據填充「f」字段,然後輸入myApp.exec()循環。 myApp是一個簡單的QApplication,包含一個QLabel,顯示一個QPixmap,由QImage構建,我可以用計算的數據填充它的「bits()」數據(這裏使用一些不相關的映射)。然後,「process」函數進行連續的計算,更新QImage的「bits」數據(「bits」指針通過f結構已知),然後強制GUI自行更新。

這裏有一些代碼段:

init(f){ 
... 
pthread_create(&(f->qt_tid),NULL,&qtimgdisplay_main_thread,f); 
... 
} 

process(f){ 
... 
do_computation(); 
do_ update(f->bits); 
f->myLabel->repaint(); 
... 
} 

static void *qtimgdisplay_main_thread(void *arg){ 
    FStructure *f = (FStructure *)arg; 

    char arg0[] = "programName"; 
    char arg1[] = "arg"; 
    char arg2[] = "another arg"; 
    char* argv[] = { &arg0[0], &arg1[0], &arg2[0], NULL }; 
    int argc = (int)(sizeof(argv)/sizeof(argv[0])) - 1; 

    f->myApp = new QApplication(argc, &argv[0]); 

    //we create a image 
    QImage image(f->winwidth,f->winheight,QImage::Format_RGB32); 

    f->bits=image.bits(); //pointer to the underlying data image 

    f->myLabel=new QLabel(); 
    f->myLabel->setPixmap(QPixmap::fromImage(image)); 
    f->myLabel->show(); 

    f->myApp->exec(); 

    return NULL; 
} 

雖然有些工作(execpts一些隨機段錯誤),與溶液中的問題是,它(正確地)顯示:

的QPixmap:不是可以安全地在GUI線程之外使用像素映射

這是完全正確的,因爲QWidgets不可重入。因此,我嘗試以異步的方式(我仍然不得不想象如何從我的進程()發出一個信號到QLabel myLabel)發送一個Repaint流程「:

f->myLabel->repaint(); 

有:

f->myApp->postEvent(f->myLabel,new QPaintEvent(f->myLabel->rect())); 

災難性結果是QT GUI不更新自身;更多的,控制檯顯示:

了QPainter ::開始:小工具畫只能作爲開始的的paintEvent

結果最後,我想用一些「聰明」(即我發現這裏更換同上面的行: http://www.qtforum.org/article/18253/qpaintevent-problem-in-qt4.html),即:

QPaintEvent *pe = new QPaintEvent(f->myLabel->rect()); 
    f->myLabel->setAttribute(Qt::WA_WState_InPaintEvent, true); 
    f->myApp->sendEvent(s->myLabel,f->myLabel->rect()); 
    f->myLabel->setAttribute(Qt::WA_WState_InPaintEvent, false); 

的夢幻般的結果是,它甚至沒有編譯:

錯誤:呼叫沒有匹配函數 '的QApplication ::的SendEvent(QLabel * &,查閱QRect)'

我迷路了。請有人幫忙嗎?

這些是我考慮一些可能的解決方案:

1)使qtimgdisplay_main_thread一個線程的QThread,而不是並行線程的線程,雖然我不知道這將是任何幫助;

2)試圖從我的「進程」發出一些信號到f-> myApp或f-> myLabel,但我不知道如何做到這一點,因爲「process」運行在非QThread(和有沒有辦法訪問父線程)

3)創建和銷燬一個新的QApplication,與所有關聯的QLabel和QImage內的「過程」,但這只是在正常情況下做的壓倒性和白癡。

感謝您閱讀所有這些內容。如果可能,請嘗試通過代碼(而不是其他文檔)提供給我一個提示。

編輯:看來,如果我使用:的

f->myLabel->update(); 

代替:

f->myLabel->repaint(); 

在我的 「過程」。

任何人都可以證實這是正確的解決方案嗎?

回答

0

回答我的問題:任何人誰可能是感興趣的同一主題中,請看到這個答案:https://stackoverflow.com/a/10882705/1284631通過https://stackoverflow.com/users/1329652/kuba-ober(使用QCoreApplication::postEvent法)和我自己的解決方案,提供了一個很好的解決方案,它可以歸結爲寫作並實例化一個特殊用途的QObject派生方法 - 命令信號發射類用於與QT接口(即一個類的方法與其他C++方法一樣被調用,但他們做的唯一有用的事情是向QT發送信號QObject對象)。

相關問題