[英]Best way to threading when with/as is needed (python, pyqt)
我正在嘗試使用qthread運行worker類。 如果使用workerObject = workerClass()實例化了工作程序,我可以做到這一點沒有問題。 如果worker類需要始終執行出口,該怎么辦?
下面是嘗試執行此操作的示例代碼。 不幸的是,通過運行此命令, 退出函數無法執行,並且很可能是因為線程不知道with / as語句
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import sys
import time
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(400, 284)
self.textEdit = QtGui.QTextEdit(Dialog)
self.textEdit.setGeometry(QtCore.QRect(20, 20, 361, 191))
self.textEdit.setObjectName(_fromUtf8("textEdit"))
self.pushButton = QtGui.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(170, 250, 75, 23))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))
self.pushButton.setText(_translate("Dialog", "Print", None))
class UI_MainWindow(QtGui.QMainWindow, Ui_Dialog):
def __init__(self, parent=None):
super(UI_MainWindow, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.run)
def run(self):
self.t = QThread()
self.x = None
with worker() as self.x:
self.x.signal.connect(self.write)
self.x.moveToThread(t)
t.started.connect(self.x.run)
t.start()
@pyqtSlot(str)
def write(self, text):
self.textEdit.append("Running")
qtObject.processEvents()
class worker(QObject):
signal = pyqtSignal(str)
def __init__(self, parent = None):
super(worker, self).__init__(parent)
def __enter__(self):
return self
def run(self):
self.signal.emit("Running")
time.wait(5)
raise Exception
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
self.signal.emit("Exception")
def main(qtObject, guiObj):
guiObj.show()
qtObject.exec_()
qtObject.processEvents()
qtObject = QtGui.QApplication(sys.argv)
guiObj = UI_MainWindow()
main(qtObject, guiObj)
LE:上下文涉及需要在QTextEdit窗口中打印來自worker類的任何失敗消息。 在工作程序類執行期間引發的任何異常都將在其退出函數中進行處理,以便無論發生什么錯誤,該腳本都會以優美的結尾向用戶提供有意義的信息和指令。
__exit__
函數確實得到執行,問題是由於線程的非阻塞性質, with
構造在工作程序“完成”並引發異常之前立即終止(調用worker.__exit__
)。
達到你想要的一種方法是圍繞代碼worker.run()
與try/except
聲明捕捉任何未處理的異常,並執行任何清理或發射的信號。
def run(self):
try:
self.signal.emit("Running")
time.sleep(5)
raise Exception
except:
self.signal.emit("Exception")
從user3419537解決方案開始,最后給出以下解決方案。 第二個信號(statusSignal)用於將所有與異常相關的信息帶回主類,以便可以調用退出函數。
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import sys
import time
class err(Exception):
def __init__(self, *args):
self.args = [a for a in args]
mainThread = QtCore.QThread.currentThread()
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(400, 284)
self.textEdit = QtGui.QTextEdit(Dialog)
self.textEdit.setGeometry(QtCore.QRect(20, 20, 361, 191))
self.textEdit.setObjectName(_fromUtf8("textEdit"))
self.pushButton = QtGui.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(170, 250, 75, 23))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))
self.pushButton.setText(_translate("Dialog", "Print", None))
class UI_MainWindow(QtGui.QMainWindow, Ui_Dialog):
def __init__(self, parent=None):
super(UI_MainWindow, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.run)
def run(self):
self.t = QThread()
self.x = worker()
self.x.signal.connect(self.write)
self.x.statusSignal.connect(self.runExit)
self.x.moveToThread(self.t)
self.t.started.connect(self.x.run)
self.t.start()
@pyqtSlot(str)
def write(self, text):
self.textEdit.append(text)
qtObject.processEvents()
@pyqtSlot(object, object, object)
def runExit(self, exc_type, exc_value, exc_traceback):
self.t2 = QThread()
self.x.moveToThread(self.t2)
self.t2.started.connect(lambda: self.x.__exit__(exc_type, exc_value, exc_traceback))
self.t2.start()
class worker(QObject):
signal = pyqtSignal(str)
statusSignal = pyqtSignal(object, object, object)
def __init__(self, parent = None):
super(worker, self).__init__(parent)
def run(self):
try:
self.signal.emit("Run")
time.sleep(2)
self.moveToThread(mainThread)
raise err("err message")
except err:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.statusSignal.emit(exc_type, exc_value, exc_traceback)
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
self.signal.emit(exc_value.args[0])
def main(qtObject, guiObj):
guiObj.show()
qtObject.exec_()
qtObject.processEvents()
qtObject = QtGui.QApplication(sys.argv)
guiObj = UI_MainWindow()
main(qtObject, guiObj)
很可能仍然需要對代碼進行一些調整,但是就目前而言,它可以完美運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.