正常关闭PySide2中的QThread

时间:2019-07-09 12:05:40

标签: python python-multithreading pyside2

因此,我正在使用PySide2编写应用程序,该应用程序会将所有内容从stdout重定向到中间queue.QueueQueue发出一个信号,该信号将由QThread处理,并将队列中的所有字符串附加到QTextEdit。

我已经环顾了四周,但不幸的是,似乎没有什么真正适合我。

那是我指的代码。

from PySide2 import QtWidgets, QtGui, QtCore

import sys
from queue import Queue


class WriteStream(object):
    """ Redirects sys.stdout to a thread-safe Queue

    Arguments:
        object {object} -- base class
    """
    def __init__(self, queue):
        self.queue = queue

    def write(self, msg):
        self.queue.put(msg)

    def flush(self):
        """ Passing to create non-blocking stream (?!)
            https://docs.python.org/3/library/io.html#io.IOBase.flush
        """
        pass


class WriteStreamThread(QtCore.QThread):
    queue_updated = QtCore.Signal(str)

    def __init__(self, queue):
        super(WriteStreamThread, self).__init__()
        self.stop = False
        self.queue = queue

    def set_stop(self):
        self.stop = True
        self.wait() # waits till finished signal has been emitted

    def run(self):
        while not self.stop:    # i guess this is blocking
            msg = self.queue.get()
            self.queue_updated.emit(msg)
            self.sleep(1)   # if commented out, app crashes
        self.finished.emit()


class Verifyr(QtWidgets.QMainWindow):
    def __init__(self, queue, parent=None):
        super(Verifyr, self).__init__(parent)
        self.centralwidget = QtWidgets.QWidget(self)
        layout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.textedit = QtWidgets.QTextEdit(self)
        layout.addWidget(self.textedit)
        self.setLayout(layout)
        self.setCentralWidget(self.centralwidget)
        print("Verifyr initialised...")

        self.listener_thread = WriteStreamThread(queue)
        self.listener_thread.queue_updated.connect(self._log_to_qtextedit)
        self.listener_thread.start()

    @QtCore.Slot(str)
    def _log_to_qtextedit(self, msg):
        self.textedit.insertPlainText(msg)


if __name__ == '__main__':
    # create Queue to be passed to WriteStream and WriteStreamListener
    queue = Queue()
    # redirect stdout to WriteStream()
    sys.stdout = WriteStream(queue)
    print("Redirected sys.stdout to WriteStream")

    # launching the app
    app = QtWidgets.QApplication(sys.argv)
    window = Verifyr(queue)
    app.aboutToQuit.connect(window.listener_thread.set_stop)
    window.show()
    sys.exit(app.exec_())

WriteStreamThread中,我使用一个while循环,该循环不断发出信号,并被主应用程序捕获以附加到其QTextEdit。当我注释掉self.sleep(1)时,应用程序将陷入无限循环。如果没有,则该线程将退出。

有人可以向我解释一下吗?

更新: 就像我在评论中提到的那样,我已经找到了错误...这是run()的更新的WriteStreamThread方法:

def run(self):
    while not self.stop:
        try:
            msg = self.queue.get(block=False) # nasty little kwarg
        except:
            msg = "No items in queue. Sleeping 1sec.."
            self.sleep(1)
        self.queue_updated.emit(msg)
    self.finished.emit()    # optional

1 个答案:

答案 0 :(得分:1)

我发现了错误。 queue.get()的{​​{1}}方法中的run()被阻止了。 将其更改为WriteStreamThread并用try / catch包围即可完成工作。 愚蠢的我...