2015-11-06 102 views
1

我正在Qt 5.5與Qt Creator一起工作。 我有一個名爲settingsWindow的大類,正如名稱所示,它負責各種設置。然後使用這些設置來啓動一些QDialog,這些QDialog在qGraphicsView中的場景中顯示非常複雜的動畫,並通過QCoreApplication :: processEvents()不斷更新,這些動畫反過來保持GUI的響應。動畫是通過QDialog的start()方法啓動的。 我想同時運行這些QDialog,例如通過按鈕啓動,在同一時刻啓動所有這些QDialog。我試過使用一個包裝器,也就是從QObject繼承的一個簡單的類,每次將它分配給不同的線程,但是如果我啓動一個QDialog,一切正常,當我開始第二個時,第一個「塊」(動畫停止並且僅在第二個Qdialog中動畫可見)。 我唯一的解決方案是爲它們中的每一個啓動一個單獨的QProcess(這樣我確信它們分開運行並且位於不同的線程中),但是我需要重寫邏輯(每個QDialog的單獨程序)。如何在不同線程中同時運行多個QDialog?

任何更簡單的解決方案?先謝謝你。

+0

你如何顯示對話框?你叫'QDialog :: exec()'? – jpo38

+0

我調用'QDialog :: show()',然後'name_of_the_dialog-> start()',開始動畫。 – Michael

回答

1

它不能在一個進程內完成。任何觸及QWidget的東西只能在主線程中運行。你的代碼碰巧運行的是巧合,你依賴於未定義的行爲,而Qt從來沒有這樣用過。沒有這方面的測試,依此類推:你是獨立的,你必須深入挖掘Qt代碼來弄清楚改變什麼來允許任何這些。

如果你這樣做太複雜的GUI線程渲染的動畫,你堅持使用傳統的小工具,你必須通過他們使用QtConcurrent::runQPainter一個QImage,因爲異步工作方式來呈現。異步工作人員然後將圖像發送到對話框,然後後者會將它們粘貼到屏幕上。

有關兩個相關示例的鏈接,請參見this answer

否則,請使用QML。對於大多數情況,從CPU的角度來看,QML動畫幾乎是不可操作的。 GPU執行所有渲染,並且表現令人讚歎。

多處理方法當然也是可行的。隨意使用指定用於進程間通信的管道的隨機名稱的參數來啓動相同的可執行文件,並修改行爲(第1對第2對話等)。請參閱this answer瞭解如何輕鬆啓動自己。

+0

你的意思是「你的代碼恰好運行在什麼意義上是一個巧合」?你是否想要在一個線程中移動一個QDialog? 我想我會繼續爲每個QDialog提供一個單獨的過程。關於QDialog之間的通信,我不需要進程間通信(它們實際上不會返回任何內容,而且它們可以處理來自settingsWindow的完全不同的變量)。 「動畫」實際上是一種圖形構造,從源節點開始,嘗試到達目標節點,向場景添加新的點和線。 QPainter是一種很好的渲染方式嗎? – Michael

+0

*你是否想要在一個線程中移動QDialog?*是的。不要這樣做。這不應該起作用,它不被支持,如果你有任何問題,你自己完全獨立(除非你僱用某人,當然)。 *「動畫」實際上是一個圖形構造,從源節點開始並嘗試到達目標節點*將數據和運行於其上的算法從可視化中分離出來。那是你的問題。渲染速度不太慢,很可能。不過,你的計算正在放慢渲染速度。 –

0

很難提供任何代碼。

您可以嘗試爲每個對話框創建一個線程,然後將一個對話框移動到每個線程(使用QObject::moveToThread)。

每個線程都必須讓其他人有機會在一段時間內執行指令(調用QThread::yieldCurrentThreadQThread::sleep)。否則,如果一個線程處於一個巨大的循環中,那麼它將永遠不會給其他人一個做某事的機會。

+0

是的,事實上,這是一個巨大的循環,導致一個線程阻塞另一個。我認爲,由於我有一個多核處理器,每個生成的線程都會自動分配給另一個核心,但似乎並不是這種情況。奇怪的是,無論如何,GUI在每個QDialog中都是響應式的(我在每個QDialog中也有一個簡單的記時器,顯示自啓動以來的時間,並且它可以持續順暢地運行)。 你如何建議實施停止線程讓其他人繼續?每個100 ms從一個線程交換到另一個線程的「QTimer」?它不會造成開銷嗎? – Michael

+0

嘗試從線程調用'yieldCurrentThread',這會將控件傳遞給另一個控件。 – jpo38

+0

如何? 如果我創建了兩個QDialogs,那麼執行 'QThread * t1 = new QThread; QThread * t2 = new QThread; dialog1-> moveToThread(t1); dialog2-> moveToThread(t2); dialog1-> show(); dialog2-> show(); dialog1-> start(); dialog2-> start();' 我應該使用'QTimer'還是每個'n'睡眠/產生一個線程並繼續使用另一個? – Michael