首页 > 解决方案 > PyQt5 从主模块外部实时登录 QTextedit

问题描述

我花了很长时间才在这里发布我的第一个问题,因为我过去所有问题的所有答案都已经在这里了。但是我还没有找到解决这个问题的方法,所以我们开始吧:

描述:在我的应用程序中,我想在 QTextEdit 小部件中显示实时日志记录信息。为了让它工作,我实现了我在这里找到的解决方案。

问题:上面链接中的代码就像一个魅力,只要所有执行的函数都是主窗口类的一部分。但是对于我的应用程序,我需要它在主模块之外工作。我希望能够从外部函数获取实时日志信息(每行一行)(例如:当“someProcess”函数位于另一个模块中时,请参见下面的代码)。当我尝试这样做时,一切正常,但它不会像以前那样显示每行的日志信息行,而是在外部函数完成后立即显示所有行。

我认为这是合乎逻辑的,因为在外部函数中,外部模块中的记录器对象没有发出信号。但我无法用一种简单(或任何)的方式来完成这一点。

主文件

import sys
import time
import logging
import othermodule as om
from PyQt5.QtCore import QObject, pyqtSignal, QThread
from PyQt5.QtWidgets import QWidget, QTextEdit, QPushButton, QVBoxLayout, QApplication

logger = logging.getLogger(__name__)


class ConsoleWindowLogHandler(logging.Handler, QObject):
    sigLog = pyqtSignal(str)
    def __init__(self):
        logging.Handler.__init__(self)
        QObject.__init__(self)

    def emit(self, logRecord):
        message = str(logRecord.getMessage())
        self.sigLog.emit(message)


class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()

        # Layout
        textBox = QTextEdit()
        textBox.setReadOnly(True)
        self.button = QPushButton('Click')
        vertLayout = QVBoxLayout()
        vertLayout.addWidget(textBox)
        vertLayout.addWidget(self.button)
        self.setLayout(vertLayout)

        # Connect button
        
        self.button.clicked.connect(self.buttonPressed)

        # Thread
        self.bee = Worker(self.test, ())
        self.bee.finished.connect(self.restoreUi)
        self.bee.terminate()

        # Console handler
        consoleHandler = ConsoleWindowLogHandler()
        consoleHandler.sigLog.connect(textBox.append)
        logger.addHandler(consoleHandler)

    def buttonPressed(self):
        self.button.setEnabled(False)
        self.bee.start()

    def restoreUi(self):
        self.button.setEnabled(True)

    def test(self):
        logger.error('Starting')
        om.someProcess()

class Worker(QThread):
    def __init__(self, func, args):
        super(Worker, self).__init__()
        self.func = func
        self.args = args

    def run(self):
        self.func(*self.args)


def main():
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

其他模块.py

import time
import logging

logger = logging.getLogger(__name__)

def someProcess(self):
    logger.error("starting")
    for i in range(10):
        logger.error("line%d" % i)  # Every iteration, I want to display this line per line 
                                    # in the textbox on the main window
        time.sleep(2)    # in my own code, here comes a time consuming task 

标签: pythonloggingpyqt5qthread

解决方案


错误是因为 ConsoleWindowLogHandler 只处理 main.py 中创建的 logger 的信息,而不处理 othermodule.py 中创建的 logger 的信息,解决方法是指定 ConsoleWindowLogHandler 也是 othermodule.py 中创建的 logger 的处理程序:

# Console handler
consoleHandler = ConsoleWindowLogHandler()
consoleHandler.sigLog.connect(textBox.append)
logger.addHandler(consoleHandler)
om.logger.addHandler(consoleHandler)

注意:虽然这很简单,但您应该更改def someProcess(self):def someProcess():


推荐阅读