将外部线程日志连接到 PyQt5 QPlainTextEdit

Connecting external threaded log to PyQt5 QPlainTextEdit

我是 PyQt 和一般处理程序的新手,我尝试阅读我找到的每个回购协议,但我不知道如何解决我的问题,正如你在我的代码中看到的那样,我正在执行在后台记录线程,我试图在我的 QPlainTextEdit 控制台中显示日志——出于某种原因,我可以在我的终端中看到日志,而 text_box 根本没有得到日志, 我将非常感谢你的聪明帮助。

import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import os
import threading
import json


class ConsolePanelHandler(logging.Handler):

    def __init__(self, stream):
        # super().__init__()
        logging.Handler.__init__(self)
        # logging.StreamHandler.__init__(self, stream)
        self.stream = stream

    def handle(self, record):
        rv = self.filter(record)
        if rv:
            self.acquire()
            try:
                self.emit(record)
            finally:
                self.release()
        return rv

    def emit(self, record):
        try:
            stream = self.stream
            stream(self.format(record))
        except RecursionError:
            raise
        except Exception:
            self.handleError(self.format(record))


  

def thread():
    for index in range(20):
        logging.warning('scheiBe '+str(index))
        time.sleep(1)

class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()


            layout = QVBoxLayout()


            self.continue_ = QPushButton("Continue")
            self.continue_.setStyleSheet("background-color: green")
            self.continue_.setFont(QFont('SansSerif', 10))
            self.continue_.setFixedSize(QSize(300, 22))


            self.pause = QPushButton("Pause")
            self.pause.setStyleSheet("background-color: orange")
            self.pause.setFont(QFont('SansSerif', 10))
            self.pause.setFixedSize(QSize(300, 22))
      

            self.stop = QPushButton("Stop")
            self.stop.setStyleSheet("background-color: #FD4B4B")
            self.stop.setFont(QFont('SansSerif', 10))
            self.stop.setFixedSize(QSize(300, 22))
            


            self.text_box = QPlainTextEdit()
            self.text_box.setPlaceholderText("Bugs will be printed here")
            self.text_box.setReadOnly(True)
            logging.getLogger().addHandler(self.text_box)
            logging.getLogger().setLevel(logging.DEBUG)

            ConsolePanelHandler(self.appendDebug , logging.DEBUG)
            self.text_box.moveCursor(QTextCursor.End)

           
            layout.addWidget(self.continue_)
            layout.addWidget(self.pause)
            layout.addWidget(self.stop)
            layout.addWidget(self.text_box)
            
            

            self.w = QWidget()
            self.w.setLayout(layout)
            self.setCentralWidget(self.w)                                     
            thread1 = threading.Thread(target=thread, args=(), daemon=True)
            thread1.start()
            self.show()

        def closeEvent(self, event):
            close = QMessageBox()
            close.setText("Are you sure want to stop and exit?")
            close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
            close = close.exec()

            if close == QMessageBox.Yes:
                sys.exit()
            else:
                event.ignore()
            

        def appendDebug(self, string):
            self.text_box.appendPlainText(string +'\n')

        


if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    sys.exit(app.exec())

首先,您不应传递更新 text_area 的函数,而应创建一个 pyqtSignal 来更新 text_area 并将其传递给 ConsolePanelHandler

ConsolePanelHandler 添加为处理程序而不是 text_arealogging.getLogger().addHandler()

建议使用QThread而不是threading.Thread

这是完整的更新代码。

# import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import os
import sys
import threading
import json
import logging


class ConsolePanelHandler(logging.Handler):

    def __init__(self, sig):
        # super().__init__()
        logging.Handler.__init__(self)
        # logging.StreamHandler.__init__(self, stream)
        self.stream = sig

    def handle(self, record):
        rv = self.filter(record)
        if rv:
            self.acquire()
            try:
                self.emit(record)
            finally:
                self.release()
        return rv

    def emit(self, record):
        try:
            self.stream.emit(self.format(record))
        except RecursionError:
            raise
        except Exception:
            self.handleError(record)


class thread(QThread):
    def run(self) -> None:
        for index in range(20):
            logging.warning('scheiBe ' + str(index))
            self.sleep(1)

class MainWindow(QMainWindow):
    sig = pyqtSignal(str)
    def __init__(self):
        super().__init__()

        self.layout = QVBoxLayout()

        self.continue_ = QPushButton("Continue")
        self.continue_.setStyleSheet("background-color: green")
        self.continue_.setFont(QFont('SansSerif', 10))
        self.continue_.setFixedSize(QSize(300, 22))

        self.pause = QPushButton("Pause")
        self.pause.setStyleSheet("background-color: orange")
        self.pause.setFont(QFont('SansSerif', 10))
        self.pause.setFixedSize(QSize(300, 22))

        self.stop = QPushButton("Stop")
        self.stop.setStyleSheet("background-color: #FD4B4B")
        self.stop.setFont(QFont('SansSerif', 10))
        self.stop.setFixedSize(QSize(300, 22))
        self.c = ConsolePanelHandler(self.sig)

        self.text_box = QPlainTextEdit()
        self.text_box.setPlaceholderText("Bugs will be printed here")
        self.text_box.setReadOnly(True)
        logging.getLogger().addHandler(self.c)
        logging.getLogger().setLevel(logging.DEBUG)

        self.sig.connect(self.appendDebug)

        self.text_box.moveCursor(QTextCursor.End)

        self.layout.addWidget(self.continue_)
        self.layout.addWidget(self.pause)
        self.layout.addWidget(self.stop)
        self.layout.addWidget(self.text_box)

        self.w = QWidget()
        self.w.setLayout(self.layout)
        self.setCentralWidget(self.w)
        self.thread1 = thread(self) # self is parent for Qthread so Qthread will be destroyed when it's parent no longer exist
        self.thread1.start()
        self.show()

    def closeEvent(self, event):
        close = QMessageBox()
        close.setText("Are you sure want to stop and exit?")
        close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
        close = close.exec()

        if close == QMessageBox.Yes:
            self.thread1.terminate()
            sys.exit()
        else:
            event.ignore()

    @pyqtSlot(str)
    def appendDebug(self, string):
        self.text_box.appendPlainText(string + '\n')


if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    sys.exit(app.exec())