以下用壹個簡單例子來表現如何用signal/slot信號槽來退出線程。
若有壹個按鈕,點擊開始線程,再次點擊退出線程,線程的工作為打印a(1-20)然後b(1-20),線程代碼如下:
[python]?view plain?copy
class?UpdateThread(QThread):?
def?__init__(self,?parent=None):?
super(UpdateThread,?self).__init__(parent)?
self.flag?=?1#?用來判斷循環是否繼續的標誌,通過改變該標誌來使得線程中run函數退出?
def?run(self):?
table?=?['a',?'b',?'c',?'d?',?'e',?'f',?'g']?
for?i?in?range(6):?
if?self.flag?==?1:?
print?table[i]?
for?m?in?range(20):?
print?m?
time.sleep(0.5)?
else:?
break?
print?'close'#?輸出標明線程run函數已經退出?
def?stop(self):?
print?'setting?flag?false'?
self.flag?=?0?
print?self.flag?
壹開始因為python的threading沒有線程退出的api,了解到QThread有實現線程的阻塞,退出,強制退出等api,於是就將線程繼承了QThread,但是在gui界面的按鈕邏輯中寫上mythread.wait()或者是quit()還是terminate()都無法對線程產生影響(可能是當時沒有使用信號槽機制,所以不起作用),然後自己來寫壹個stop函數用來修改線程中的壹個標誌,使得run函數中的循環停止,然後就如上代碼所示,在按鈕邏輯中如下所寫(錯誤示範):[python]?view plain?copy
def?update_db():#?error?
self.new_thread1?=?UpdateDbThread()?
if?self.update_tag?==?0:?
self.update_tag?=?1?
self.new_thread1.start()?
else:?
self.update_tag?=?0?
self.new_thread1.stop()?
運行之後發現stop函數雖然改變了self.flag的值,但是循環中判斷語句中flag的值依然為1,循環並沒有停止,然後就去查閱資料,以及上stackoverflow尋找答案,最終知道了線程需要通過信號槽機制來響應,所以便去查閱qt的signal/slot的相關信息,修改按鈕代碼如下:
[python]?view plain?copy
class?mywidget(Qwidget):
sin?=?pyqtSignal()#?提前申明?
def?__init__(self):?
...?
self.new_thread1?=?UpdateDbThread()?
self.sin.connect(self.new_thread1.stop)?
def?update_db():?
if?self.update_tag?==?0:
self.update_tag?=?1?
self.new_thread1.start()
else:
self.update_tag?=?0
self.sin.emit()?
[python]?view plain?copy
</pre><p></p><pre>?
pyqtSignal信號的定義不可以寫在update_db方法中,也不可以寫在init()初始化方法中,原因如下(來自stackoverflow):
所以我們就在init方法之前定義好信號sin,然後連接上線程的stop方法。點擊按鈕發送信號,就好改變線程的標誌,然後從循環中退出,運行結果如下:
為了便於貼圖,我將循環輸出改為了10:
線程正常退出,目標達成。可以根據自己的需要重寫run方法。
還有需要註意的是,不可以在方法中寫上 mythread = update_db() ,這樣在運行時會報錯,destroyed while thread is running,因為在方法中mythread是壹個局部變量,當方法結束時,python的垃圾回收機制就會自動銷毀,然後就會出現以上錯誤,所以必須在mythread的前面加上self,使得線程成為全局變量。