問題是關於將現有的基於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();
在我的 「過程」。
任何人都可以證實這是正確的解決方案嗎?