Python 在pyqt中显示日志的最佳方法?
我目前正在使用qt designer开发GUI。我想知道我应该如何在GUI上打印字符串,就像一个日志窗口一样。我正在使用pyqt5。听起来您可能想使用设置为只读的小部件 考虑将背景颜色更改为灰色,以提示用户该颜色不可编辑。它也取决于你是否希望它是可滚动的或文本可选择的Python 在pyqt中显示日志的最佳方法?,python,pyqt,qt-designer,Python,Pyqt,Qt Designer,我目前正在使用qt designer开发GUI。我想知道我应该如何在GUI上打印字符串,就像一个日志窗口一样。我正在使用pyqt5。听起来您可能想使用设置为只读的小部件 考虑将背景颜色更改为灰色,以提示用户该颜色不可编辑。它也取决于你是否希望它是可滚动的或文本可选择的 可以开始对QPlainTextEdit进行子类化,以滚动输出、保存到文件,等等。如果使用Python日志记录模块,可以轻松创建自定义日志处理程序,将日志消息传递到QPlainTextEdit实例(如Christopher所述) 要
可以开始对QPlainTextEdit进行子类化,以滚动输出、保存到文件,等等。如果使用Python
日志记录
模块,可以轻松创建自定义日志处理程序,将日志消息传递到QPlainTextEdit
实例(如Christopher所述)
要做到这一点,首先要创建一个子类logging.Handler
。在这个\uuuu init\uuuu
中,我们创建将包含日志的QPlainTextEdit
。这里的关键点是句柄将通过emit()
函数接收消息。因此,我们重载此函数并将消息文本传递到QPlainTextEdit
import logging
class QPlainTextEditLogger(logging.Handler):
def __init__(self, parent):
super(Logger, self).__init__()
self.widget = QPlainTextEdit(parent)
self.widget.setReadOnly(True)
def emit(self, record):
msg = self.format(record)
self.widget.textCursor().appendPlainText(msg)
def write(self, m):
pass
从该类创建一个对象,将其传递给QPlainTextEdit
(例如主窗口或布局)的父对象。然后可以为当前记录器添加此处理程序
# Set up logging to use your widget as a handler
log_handler = QPlainTextEditLogger(<parent widget>)
logging.getLogger().addHandler(log_handler)
#设置日志以将小部件用作处理程序
log_handler=QPlainTextEditLogger()
logging.getLogger().addHandler(日志处理程序)
以下是一个完整的工作示例:
改编自的PyQt5示例:
import sys
from PyQt5 import QtWidgets
import logging
# Uncomment below for terminal log messages
# logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(name)s - %(levelname)s - %(message)s')
class QTextEditLogger(logging.Handler):
def __init__(self, parent):
super().__init__()
self.widget = QtWidgets.QPlainTextEdit(parent)
self.widget.setReadOnly(True)
def emit(self, record):
msg = self.format(record)
self.widget.appendPlainText(msg)
class MyDialog(QtWidgets.QDialog, QtWidgets.QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
logTextBox = QTextEditLogger(self)
# You can format what is printed to text box
logTextBox.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
logging.getLogger().addHandler(logTextBox)
# You can control the logging level
logging.getLogger().setLevel(logging.DEBUG)
self._button = QtWidgets.QPushButton(self)
self._button.setText('Test Me')
layout = QtWidgets.QVBoxLayout()
# Add the new logging box widget to the layout
layout.addWidget(logTextBox.widget)
layout.addWidget(self._button)
self.setLayout(layout)
# Connect signal to slot
self._button.clicked.connect(self.test)
def test(self):
logging.debug('damn, a bug')
logging.info('something to remember')
logging.warning('that\'s not right')
logging.error('foobar')
app = QtWidgets.QApplication(sys.argv)
dlg = MyDialog()
dlg.show()
dlg.raise_()
sys.exit(app.exec_())
Alex的回答在单线程场景中应该是可以的,但是如果您正在登录另一个线程(QThread),您可能会收到以下警告:
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
这是因为您正在从主线程以外的线程修改GUI(self.widget.appendPlainText(msg)
),而不使用Qt信号/插槽机制
以下是我的解决方案:
#my_logger.py
导入日志记录
从PyQt5.QtCore导入pyqtSignal,QObject
类处理程序(QObject,logging.Handler):
新记录=pyqtSignal(对象)
定义初始化(自身,父级):
super()。\uuuu init\uuuu(父级)
super(logging.Handler)。\uuuu init\uuuuuu()
格式化程序=格式化程序('%(asctime)s |%(levelname)s |%(message)s |',“%d/%m/%Y%H:%m:%s')
self.setFormatter(格式化程序)
def排放(自我,记录):
msg=self.format(记录)
self.new_record.emit(msg)#线程安全版本
用法
Bing用户应该这样做:p这可能是一个愚蠢的问题,但是继承MyDialog
中的QPlainTextEditLogger
的目的是什么?我正在尝试将这个示例转换为PyQt5,如果不删除第二个继承,就无法让它工作。在其他情况下如何使用,我有带QMainWindow的*.ui,带tab(name tab_log)的QTabWidget,都是在ui文件中定义的。如何将QTextEditLogger添加到QTabWidget中的选项卡???这不是线程安全的appendPlainText
应该连接到信号而不是调用它。我收到以下错误消息:AttributeError:module'logging'没有属性'Handler'
哇,这对我来说是一个简单的复制粘贴。亚历克斯,你真是个神。我只是不能让它在PySide2上运行,因为你不能在QObject上拥有多个继承权。为了让它工作,我不得不使用旧的信号语法,如感谢,这很快!谢谢你的回答。虽然我不知道为什么,但在PySide2(5.12.0)中,双重继承对我来说不起作用。错误是“emit()接受2个位置参数,但给出了3个”。(这是signal emit函数,我认为这意味着signal对象存在一些继承问题)我的一个工作示例是使用该信号创建一个新的QThread/QObject类,并将一个实例注入日志处理程序构造函数。有点像一个例子。
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
class QTextEditLogger(logging.Handler, QtCore.QObject):
appendPlainText = QtCore.pyqtSignal(str)
def __init__(self, parent):
super().__init__()
QtCore.QObject.__init__(self)
self.widget = QtWidgets.QPlainTextEdit(parent)
self.widget.setReadOnly(True)
self.appendPlainText.connect(self.widget.appendPlainText)
def emit(self, record):
msg = self.format(record)
self.appendPlainText.emit(msg)
logTextBox = QTextEditLogger(self)
# log to text box
logTextBox.setFormatter(
logging.Formatter(
'%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s'))
logging.getLogger().addHandler(logTextBox)
logging.getLogger().setLevel(logging.DEBUG)
# log to file
fh = logging.FileHandler('my-log.log')
fh.setLevel(logging.DEBUG)
fh.setFormatter(
logging.Formatter(
'%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s'))
logging.getLogger().addHandler(fh)