PyQt5 从主模块外部实时登录 QTextedit

Posted

技术标签:

【中文标题】PyQt5 从主模块外部实时登录 QTextedit【英文标题】:PyQt5 realtime logging in QTextedit from outside main module 【发布时间】:2020-12-26 12:19:09 【问题描述】:

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

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

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

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

main.py

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 

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

以上是关于PyQt5 从主模块外部实时登录 QTextedit的主要内容,如果未能解决你的问题,请参考以下文章

如何在python pyqt5中从主窗口管理第二个窗口

[ PyQt入门教程 ] PyQt5中多线程模块QThread使用方法

使用 Celery 通过 Gevent 进行实时、同步的外部 API 查询

如何将变量从 PyQt5 UI 返回到 Main 函数 - Python

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题