我有以下问题:我们的主应用程序使用 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
在仔细阅读 stackoverflow 之后,我发现了类似的问题(这些问题并不适用于这种情况)。显然,当我从另一个线程更改主窗口中的某些内容时,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
签名与 Boost 信号相同 - 在处理 Boost 信号的插槽中,我发出新
Qt
信号,将指针传递过去 - 我现在创建了一个接收指针的新Qt插槽
当我在新插槽中打开一个新窗口时,一切正常。然而,这让我觉得非常笨拙。我是否必须像这样级联 所有Boost 信号还是有更好的方法?