简体   繁体   English

PYQt5:QThread:线程仍在运行时销毁(实例分配为 QDialog )

[英]PYQt5: QThread: Destroyed while thread is still running ( with instance assigned as QDialog )

I am encountering this problem QThread: Destroyed while thread is still running when I close the NextWindow QDialog .我遇到了这个问题 QThread: Destroyed while thread is still running 当我关闭NextWindow QDialog 时

The code I wrote is我写的代码是

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())

I have checked reference answers in PyQt5 - QThread: Destroyed while thread is still running and QThread: Destroyed while thread is still running .我已经检查了PyQt5 - QThread: Destroyed while thread is still running 和QThread: Destroyed while thread is still running 中的参考答案。

The answers are basically didnt assign instance to the QThread like答案基本上没有像 QThread 这样分配实例

self.thread = QThread(parent=self) While I did so but the issue persisted. self.thread = QThread(parent=self) 虽然我这样做了,但问题仍然存在。

The debug message of QThread: Destroyed while thread is still running can be ubiquitous but the cause of the reason can be not always the same. QThread: Destroyed while thread is still running的调试消息可能无处不在,但原因可能并不总是相同。 For this case the thread has not been ended well when you close the dialog even you include the self as对于这种情况,当您关闭对话框时,即使您将 self 作为

self.worker_thread = qtc.QThread(self)

In this case you should reject the Qthread as mentioned in the question Terminating QThread gracefully on QDialog reject()在这种情况下,您应该拒绝 Qthread,如在 QDialog reject() 上优雅地终止 QThread问题中所述

So you should add one more line in your code所以你应该在你的代码中再添加一行

self.worker_thread.start()
self.rejected.connect(self.thread.terminate)

According to the PYQT5 document根据PYQT5 文档

When the thread is terminated, all threads waiting for the thread to finish will be woken up.

Warning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.

So I would suggest to add所以我建议添加

self.rejected.connect(self.thread.quit)

or或者

self.rejected.connect(self.thread.exit)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 PyQt5 - QThread:线程仍在运行时被销毁 - PyQt5 - QThread: Destroyed while thread is still running PyQt QThread:在线程仍在运行时被销毁 - PyQt QThread: Destroyed while thread is still running PyQt5:在线程仍在运行时销毁 - PyQt5 : Destroyed while thread is still running QThread:当线程仍在Python中运行时被破坏 - QThread: Destroyed while thread is still running in Python 退出时“ QThread:线程仍在运行时被销毁” - 'QThread: Destroyed while thread is still running' on quit QThread:在线程仍在运行时被销毁 - QThread: Destroyed while thread is still running pyqt5 qthread-在另一个脚本中运行线程 - pyqt5 qthread - running thread in another script “QThread:当线程仍在运行时被破坏”从Windows cmd或IDLE运行但不是从PyCharm运行? - “QThread: Destroyed while thread is still running” when run from the Windows cmd or IDLE but not from PyCharm? QThread:在线程仍在运行时被销毁:如何正确使用 QThreads 和 QTimers? - QThread: Destroyed while thread is still running: How to proper use QThreads with QTimers? 使用Python的QtWebkit呈现基于Javascript的页面,获取QThread:在线程仍在运行时被销毁 - Using Python's QtWebkit to render Javascript-based page, get QThread: Destroyed while thread is still running
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM