次の問題があります。メインアプリケーションは、ウィンドウとユーザーインタラクションを表示するためにQtツールキットを使用しています。ただし、アプリケーションの大部分はGUI部分を認識していません。次のデザインを作成しました。
- 特定のオブジェクトのレンダリングを要求する可能性のあるシングルトンクラスがあります(OpenSceneGraphノード。ただし、これは質問には関係ありません)。
- レンダリング要求により、シングルトンは信号を送信します
- メインウィンドウクラス(Qtを使用)には、オブジェクトのレンダリングを処理するためのスロットがあります
- 現在、スロットは新しいテキスト編集ウィジェットを作成し、それを
QMdiArea
メインウィンドウのに配置するだけです。
ただし、新しいウィジェットを作成しようとすると、必然的にアプリケーションがクラッシュします。エラーメッセージ領域:
QObject::setParent: Cannot set parent, new parent is in a different thread
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
myApplication: ../../src/xcb_io.c:178: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted
スタックオーバーフローを熟読した後、私は同様の質問を見つけました(これはこの状況にはすぐには当てはまりませんでした)。明らかに、メインウィンドウの何かを別のスレッドから変更するとき、Qtはそれを気に入らない。しかし、私は意識的に新しいスレッドを作成しなかったので、シングルトン(の呼び出しの直後にmain関数で作成されるQApplication()
)はQtと同じスレッドにあるべきだと思いました。どうやら、私は間違っています。
これは私が行っていることを示す最小限の例です(コードの関連部分を抽出したので、例は正確には機能しません):
class Object
{
public:
};
class Singleton
{
public:
typedef boost::signals2::signal<void (Object*)> signalShowObject;
signalShowObject _showObject;
};
class MainWindow : public QMainWindow
{
public:
MainWindow()
{
Singleton::getInstance()->_showObject.connect( boost::bind(&MainWindow::showObject, this, _1) );
// Set up MDI area etc.
}
private:
QMdiArea* _mdiArea;
void showObject(Object* object)
{
// Creating a new subwindow here causes the crash. The `object` pointer is
// not used and has just been included because it models my real problem
// better.
_mdiArea->addSubWindow( new QTextEdit() )->show();
}
};
この問題を解決するための私の試みは非常に不器用でした:
- ブーストシグナルと同じシグネチャを持つクラスで新しいQtシグナルを作成しました
MainWindow
- ブースト信号を処理するスロットで、新しい
Qt
信号を出力し、ポインターを渡します - ポインタを受け取る新しいQtスロットを作成しました
新しいスロットで新しいウィンドウを開くと、すべてが機能します。しかし、これは非常に不器用だと思います。そのようなすべてのブースト信号をカスケードする必要がありますか、それともより良い方法がありますか?