我遇到以下問題:我們的主應用程序使用Qt工具包來顯示窗口和用戶交互。然而,我們應用程序的很大一部分對GUI部分一無所知。我現在創建了以下設計:在多線程的Qt應用程序中處理升壓信號
- 有一個單例類可請求呈現給定對象(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並不喜歡它。但是,我沒有自覺創建新的主題,我認爲單(這是在主函數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();
}
};
我試圖解決這個問題有一直很笨拙:
- 我在
MainWindow
類創建了一個新的Qt 信號具有相同簽名的加速信號 - 在SL OT處理該升壓信號,我發射新
Qt
信號,使指針移到 - 我現在創建接收指針新的Qt槽
當我在新的插槽打開一個新的窗口,一切正常。但是,這讓我覺得很笨拙。我是否需要級聯全部提升這樣的信號還是有更好的方法?
只是要清楚。每個gui操作必須在QApplication線程中完成。如果你想檢查你的方法是否在正確的線程調用中使用qDebug()<< thread()<< QThread :: currentThread();告訴我們showObject成員中該調試的輸出是什麼。 –
@KamilKlimek我在我的「真實」應用程序中獲得了線程ID,它們確實不同。 – Gnosophilon
你可以調用插槽,然後用QMetaObject :: invokeMethod –