2016-03-01 115 views
2

我已經實現了Qt Threading docs中描述的工作模式版本。如何向線程發送無信號?

我使用Signals/Slots在工作線程和主線程之間發送數據。

當定義Signal時,我將參數簽名類型設置爲object,因爲我相信它應該允許我通過Signal傳遞任何python對象。

result_ready = QtCore.Signal(object) 

然而,當我試圖通過Signal通過None崩潰蟒蛇。只有在嘗試跨線程傳遞Signal時纔會發生這種情況。如果我註釋掉self.worker.moveToThread(self.thread)這一行,它將起作用,並且None已成功通過Signal

爲什麼在這種情況下我無法通過None?我使用PySide 1.2.2Qt 4.8.5

import sys 

from PySide import QtCore, QtGui 


class Worker(QtCore.QObject): 

    result_ready = QtCore.Signal(object) 

    @QtCore.Slot() 
    def work(self): 
     print 'In Worker' 

     # This works 
     self.result_ready.emit('Value') 

     # This causes python to crash 
     self.result_ready.emit(None) 


class Main(QtGui.QWidget): 

    def __init__(self): 
     super(Main, self).__init__() 
     self.ui_lay = QtGui.QVBoxLayout() 
     self.setLayout(self.ui_lay) 
     self.ui_btn = QtGui.QPushButton('Test', self) 
     self.ui_lay.addWidget(self.ui_btn) 
     self.ui_lay.addStretch() 
     self.setGeometry(400, 400, 400, 400) 
     self.worker = Worker() 
     self.thread = QtCore.QThread(self) 
     self.worker.moveToThread(self.thread) 
     self.thread.start() 
     self.ui_btn.clicked.connect(self.worker.work) 
     self.worker.result_ready.connect(self.handle_worker_result) 

    @QtCore.Slot(object) 
    def handle_worker_result(self, result=None): 
     print 'Handling output', result 

    def closeEvent(self, event): 
     self.thread.quit() 
     self.thread.wait() 
     super(Main, self).closeEvent(event) 


if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    obj = Main() 
    obj.show() 
    app.exec_() 

回答

2

這看起來像一個PySide錯誤。相同的示例代碼與PyQt4完全相同。

問題出在type of signal connection。對於跨線程信號,除非另有說明,否則將使用QueuedConnection。如果示例代碼中的連接類型更改爲DirectConnection,它將按預期工作 - 但當然它不再是線程安全的。

A QueuedConnection會將事件發送到接收線程的事件隊列。但爲了這是線程安全的,Qt必須序列化發出的參數。然而,PySide顯然需要在這裏注入一些魔力來處理Qt不知道的python類型。如果我不得不猜測,我敢打賭,PySide錯誤地將python None對象轉換爲C++ NULL指針,這在稍後顯然會有不好的後果。

如果你想解決這個問題,我想你可以發出你自己的哨兵對象作爲None的佔位符。

UPDATE

發現的bug,PYSIDE-17,這是張貼在2012年3月!可悲的是,建議的補丁似乎從未被審查過。

1

如果你改變你的信號爲適當的類,那麼它對我來說工作正常。例如:

result_ready = QtCore.Signal(str) 

這在兩種情況下均有效。

根據文檔

信號可以使用QtCore.Signal()類來定義。 Python類型和C類型可以作爲參數傳遞給它。如果您需要重載它,只需將這些類型作爲元組或列表傳遞。

https://wiki.qt.io/Signals_and_Slots_in_PySide#Using_QtCore.Signal.28.29

+0

是的,但如果使用OP實際嘗試發出的對象的類型(即'type(None)'),它將不起作用。 – ekhumoro

+0

同意..這只是一個解決方法 – Achayan