問題は、既存の C の pthread ベースのアプリケーションと QT GUI とのインターフェースについてです。実行するのは簡単な作業のように思えますが、(インターネットと試行錯誤の両方で) 検索しましたが、許容できる解決策が見つかりませんでした。
現在、アプリケーションは既存の C ライブラリを大量に使用しており、そのコードを変更するためにアクセスすることはできません。
基本的に、既存のライブラリはループを実装し、定期的にいくつかの関数を (いくつかのデータとともに) 呼び出します。私が定義できるのはそれらの関数 (関数ポインタ) だけです。
完全なアプリケーションでは、既存のライブラリ ループがこれらの関数 (別名「init」、「process」、「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 は、QImage から構築された QPixmap を表示する QLabel を含む単純な QApplication であり、その「bits()」データを計算されたデータで満たすことができます (ここでは関係のないマッピングを使用します)。
その後、「プロセス」関数は一連の計算を行い、QImage の「ビット」データを更新し (「ビット」ポインターは 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;
}
多少は機能しますが (いくつかのランダムなセグメンテーション違反が発生します)、そのソリューションの問題は、(正しく) 表示されることです。
QPixmap: GUI スレッドの外でピックスマップを使用するのは安全ではありません
QWidgets は再入可能ではないため、これは完全に真実です。
それで、私は Repaint() メッセージを非同期的に myApp に投稿しようとしました (まだ process() から QLabel myLabel にシグナルを送信する方法を想像する必要があります)、「プロセス」内を置き換えます:
f->myLabel->repaint();
と:
f->myApp->postEvent(f->myLabel,new QPaintEvent(f->myLabel->rect()));
悲惨な結果は、QT GUI 自体が更新されないことです。さらに、コンソールに次のように表示されます。
QPainter::begin: ウィジェットの描画は、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)' の呼び出しに一致する関数がありません</p>
迷っています。誰か助けてくれませんか?
これらは、私が考えたいくつかの可能な解決策です:
1) qtimgdisplay_main_thread を pthread スレッドではなく QThread スレッドにしますが、これが役立つかどうかはわかりません。
2) 「プロセス」から f->myApp または f->myLabel にいくつかのシグナルを送信しようとしていますが、「プロセス」が QThread 以外で実行されているため (方法がないため)、その方法がわかりません。親スレッドにアクセスするため)
3) 関連するすべての QLabel と QImage を「プロセス」内に配置して、新しい QApplication を作成して破棄しますが、通常の状況ではそれを行うのは圧倒され、ばかげています。
これをすべて読んでくれてありがとう。可能であれば、コード (別のドキュメントではありません) を通じてヒントを提供してください。
編集:私が使用した場合:
f->myLabel->update();
それ以外の:
f->myLabel->repaint();
私の「プロセス」の中に。
これが正しい解決策であることを誰かが確認できますか?