python - PYQt5:QThread:在线程仍在运行时被销毁(实例分配为 QDialog )
问题描述
我遇到了这个问题 QThread: Destroyed while thread is still running when I close the NextWindow QDialog。
我写的代码是
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
from pathlib import Path
from hashlib import sha1
def recursive_hashes(path):
"""Generate name and SHA1 hash of all files under the given path"""
if path.is_file():
sha1_obj = sha1()
try:
with open(path, 'rb') as handle:
while True:
data = handle.read(8192)
if not data:
break
sha1_obj.update(data)
sha1_hash = sha1_obj.hexdigest()
except PermissionError:
sha1_hash = 'Permission Denied'
yield (str(path), sha1_hash)
elif path.is_dir():
try:
for child in path.iterdir():
yield from recursive_hashes(child)
except PermissionError:
yield(str(path), 'Permission Denied')
else:
yield (str(path), 'Not a file or dir')
class Worker(qtc.QObject):
hashed = qtc.pyqtSignal(str, str)
@qtc.pyqtSlot(str)
def hash_directory(self, root):
hash_gen = recursive_hashes(Path(root))
for path, sha1_hash in hash_gen:
self.hashed.emit(path, sha1_hash)
class NextWindow(qtw.QDialog):
hash_requested = qtc.pyqtSignal(str)
def __init__(self):
"""MainWindow constructor."""
super().__init__()
layout = qtw.QFormLayout()
self.setLayout(layout)
self.file_root = qtw.QLineEdit(returnPressed=self.start_hashing)
self.go_button = qtw.QPushButton('Start Hashing', clicked=self.start_hashing)
self.results = qtw.QTableWidget(0, 2)
self.results.setHorizontalHeaderLabels(['Name', 'SHA1-sum'])
self.results.horizontalHeader().setSectionResizeMode(qtw.QHeaderView.Stretch)
self.results.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.Expanding)
layout.addRow(qtw.QLabel('SHA1 Recursive Hasher'))
layout.addRow('File Root', self.file_root)
layout.addRow('', self.go_button)
layout.addRow(self.results)
# Create a worker object and a thread
self.worker = Worker()
self.worker_thread = qtc.QThread(self)
self.worker.hashed.connect(self.add_hash_to_table)
self.hash_requested.connect(self.worker.hash_directory)
# Assign the worker to the thread and start the thread
self.worker.moveToThread(self.worker_thread)
self.worker_thread.start()
# Connect signals & slots AFTER moving the object to the thread
# End main UI code
self.show()
def add_hash_to_table(self, name, sha1_sum):
"""Add the given name and sha1 sum to the table"""
row = self.results.rowCount()
self.results.insertRow(row)
self.results.setItem(row, 0, qtw.QTableWidgetItem(name))
self.results.setItem(row, 1, qtw.QTableWidgetItem(sha1_sum))
print(name, sha1_sum)
def start_hashing(self):
"""Prepare the GUI and emit the hash_requested signal"""
# Clear the table
while self.results.rowCount() > 0:
self.results.removeRow(0)
# Get the file root and validate it
file_root = self.file_root.text()
if not Path(file_root).exists():
qtw.QMessageBox.critical(self, 'Invalid Path', 'The specified file root does not exist.')
return
# Emit the signal
self.hash_requested.emit(file_root)
#self.worker.hash_directory(file_root)
class MainWindow(qtw.QDialog):
def __init__(self):
super().__init__()
layout = qtw.QFormLayout()
self.next_button = qtw.QPushButton('Next', clicked=self.next_button)
layout.addWidget(self.next_button)
self.setLayout(layout)
def next_button(self):
dialog = NextWindow()
dialog.exec_()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())
我检查了PyQt5 - QThread: Destroyed while thread is still running 和QThread: Destroyed while thread is still running中的参考答案。
答案基本上没有将实例分配给 QThread 之类的
self.thread = QThread(parent=self) 虽然我这样做了,但问题仍然存在。
解决方案
QThread的调试消息:Destroyed while thread is still running可能无处不在,但原因可能并不总是相同的。对于这种情况,当您关闭对话框时,即使您将 self 包括在内,线程也没有很好地结束
self.worker_thread = qtc.QThread(self)
在这种情况下,您应该拒绝问题中提到的 Qthread,如在 QDialog reject() 上优雅地终止 QThread
因此,您应该在代码中再添加一行
self.worker_thread.start()
self.rejected.connect(self.thread.terminate)
推荐阅读
- python - Pandas 中带有“通配符”的查找表
- javascript - Javascript“removeEventListener”不起作用
- excel - 在 VBA 中设置查找下一个和查找上一个按钮
- python-3.x - 如何在 pyttsx3 中暂停和恢复?
- linux - Linux如何将时间格式转换为纪元时间?
- mysql - SQL 选择和连接
- django - Django 无法解压不可迭代的“Q”对象
- php - Laravel - 权限和角色包?
- akka - 在 Akka 流中处理丢弃的消息
- java - 如何导出 IntelliJ IDEA 项目以在没有 IntelliJ IDEA 的另一台机器上编译