2016-03-15 99 views
-1

我寫了一個簡單的程序,它有2個按鈕(啓動和取消)的pyQt接口。開始按鈕在後臺運行一些計算(通過啓動更新功能),並且由於線程,我仍然可以使用UI。 但是應用程序在10秒-2分鐘後崩潰。 UI只是消失,程序關閉。pyQt和線程應用程序崩潰

當我使用pythonw無需控制檯線程崩潰運行的應用程序〜25秒,但GUI後仍然有效。

#!/usr/bin/python 
import threading 
import sys 
from PyQt4 import QtGui, QtCore 
import time 
import os 


class Class(QtGui.QWidget): 

    def __init__(self): 
     #Some init variables 
     self.initUI() 

    def initUI(self): 
     #some UI 
     self.show() 

    def update(self,stop_event): 
      while True and not stop_event.isSet(): 
       self.updateSpeed() 
       self.updateDistance() 
       self.printLogs() 
       self.saveCSV() 
       self.guiUpdate() 
       time.sleep(1) 

    #gui button function 
    def initiate(self): 
     self.stop_event = threading.Event() 
     self.c_thread = threading.Thread(target = self.update, args=(self.stop_event,)) 
     self.c_thread.start() 

    #Also gui button function 
    def cancelTracking(self): 
     self.stop_event.set() 
     self.close() 

def main(): 

    app = QtGui.QApplication(sys.argv) 
    ex = Class() 
    sys.exit(app.exec_()) 
    ex.update() 

if __name__ == '__main__': 
    main() 

我不知道我是否在線程正確。我在堆棧中找到了這樣的例子。我對Python非常陌生,我第一次使用線程。

回答

1

這是最有可能是由於調用你的單獨的線程一個GUI功能。 PyQt GUI調用setText()QLineEdit不允許從一個線程。任何在主線程外有PyQt繪畫的東西都不行。解決這個問題的一種方法是在數據準備就緒時讓線程發出信號更新GUI。另一種方法是定期檢查新數據並在一段時間後更新paintEvent

#!/usr/bin/python 
import threading 
import sys 
from PyQt4 import QtGui, QtCore 
import time 
import os 


class Class(QtGui.QWidget): 

    display_update = QtCore.pyqtSignal() # ADDED 

    def __init__(self): 
     #Some init variables 
     self.initUI() 

    def initUI(self): 
     #some UI 
     self.display_update.connect(self.guiUpdate) # ADDED 
     self.show() 

    def update(self): 
     while True and not self.stop_event.isSet(): 
      self.updateSpeed() 
      self.updateDistance() 
      self.printLogs() 
      self.saveCSV() 

      # self.guiUpdate() 
      self.display_update.emit() # ADDED 

      time.sleep(1) 

    #gui button function 
    def initiate(self): 
     self.stop_event = threading.Event() 
     self.c_thread = threading.Thread(target = self.update) 
     self.c_thread.start() 

    #Also gui button function 
    def cancelTracking(self): 
     self.stop_event.set() 
     self.close() 

def main(): 

    app = QtGui.QApplication(sys.argv) 
    ex = Class() 
    sys.exit(app.exec_()) 
    # ex.update() # - this does nothing 

if __name__ == '__main__': 
    main() 

是可能會發生的另一件事是由兩個線程試圖訪問同一變量死鎖。我讀過這應該不可能在Python中,但我已經從PySide和其他Python C擴展庫的組合體驗它。

可能還需要加入對近線或使用QtGui.QApplication.aboutToQuit信號加入線程程序關閉之前。

+0

謝謝!它的工作原理就像它應該;)沒有更多的崩潰 – Karmel

1

Qt documentation for QThreads提供了使用線程兩個流行的圖案。您可以子類QThread(舊的方式),或者創建自定義QObject與工人功能,在一個單獨的QThread運行它們,你可以使用工人型號

無論哪種情況,您都無法直接從後臺線程更新GUI,因此在您的update函數中,guiUpdate調用很可能會在Qt嘗試更改任何GUI元素時崩潰。

運行後臺進程的正確方法是使用兩個QThread模式中的一個並通過SignalsSlots與主GUI線程通信。

另外,在下面的代碼位,

app = QtGui.QApplication(sys.argv) 
ex = Class() 
sys.exit(app.exec_()) 
ex.update() 

app.exec_開始事件循環和將阻塞,直到Qt的退出。在Qt退出並且ex窗口已被刪除之前,Python將不會運行ex.update()命令,因此您應該刪除該命令。

+0

ou,是的。我忘了ex.update()。我現在從GUI按鈕使用這個功能,所以我會刪除它。也感謝提示! – Karmel