python - 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
解决方案
错误是因为 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():
推荐阅读
- php - [Route: developer.variants.store] [URI: developer/{store}/products/{products}/variants] 缺少必需参数
- fiware - Fiware 时间戳避免数字舍入
- leaflet - 如何在窗格中使用leaflet.js heat?
- c# - 实体框架“SELECT IN”不使用参数
- django - Django Rest Framework 在结果中随机返回空列表,但计数仍然正确
- php - Laravel SQLSTATE [23000]:完整性约束违规:1451
- java - 比较两棵树的等于方法
- java - 如何以编程方式在执行程序节点中查找 Spark 版本?
- sql - 如何使用 PL/SQL 选择插入多行
- c# - 从c#中的嵌套无限foreach循环获取结果