Je travaille actuellement sur une interface graphique utilisant qt designer. Je me demande comment je dois procéder pour imprimer des chaînes sur l'interface graphique qui agit comme une fenêtre d'enregistrement. J'utilise pyqt5.
Si vous utilisez le module Python logging
pour créer facilement un gestionnaire de journalisation personnalisé qui transmet les messages du journal à une instance QPlainTextEdit
(comme décrit par Christopher ).
Pour ce faire, vous devez d'abord sous-classe logging.Handler
. Dans ce __init__
, Nous créons le QPlainTextEdit
qui contiendra les journaux. Le bit clé ici est que la poignée recevra des messages via la fonction emit()
. Nous surchargeons donc cette fonction et passons le texte du message dans le 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
Créez un objet à partir de cette classe, en lui passant le parent pour le QPlainTextEdit
(par exemple la fenêtre principale ou une mise en page). Vous pouvez ensuite ajouter ce gestionnaire pour l'enregistreur actuel.
# Set up logging to use your widget as a handler
log_handler = QPlainTextEditLogger(<parent widget>)
logging.getLogger().addHandler(log_handler)
Adapté de l'exemple de Todd Vanyo pour 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_())
Voici un exemple de travail complet basé sur réponse de mfitzp :
import sys
from PyQt4 import QtCore, QtGui
import logging
# Uncomment below for terminal log messages
# logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(name)s - %(levelname)s - %(message)s')
class QPlainTextEditLogger(logging.Handler):
def __init__(self, parent):
super().__init__()
self.widget = QtGui.QPlainTextEdit(parent)
self.widget.setReadOnly(True)
def emit(self, record):
msg = self.format(record)
self.widget.appendPlainText(msg)
class MyDialog(QtGui.QDialog, QPlainTextEditLogger):
def __init__(self, parent=None):
super().__init__(parent)
logTextBox = QPlainTextEditLogger(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 = QtGui.QPushButton(self)
self._button.setText('Test Me')
layout = QtGui.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')
if (__name__ == '__main__'):
app = None
if (not QtGui.QApplication.instance()):
app = QtGui.QApplication([])
dlg = MyDialog()
dlg.show()
dlg.raise_()
if (app):
app.exec_()
La réponse d'Alex devrait être correcte dans un scénario à un seul thread, mais si vous vous connectez à un autre thread (QThread), vous pouvez obtenir l'avertissement suivant:
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Cela est dû au fait que vous modifiez l'interface graphique (self.widget.appendPlainText(msg)
) à partir d'un thread autre que le thread principal sans utiliser le mécanisme Qt Signal/Slot.
Voici ma solution:
# my_logger.py
import logging
from PyQt5.QtCore import pyqtSignal, QObject
class Handler(QObject, logging.Handler):
new_record = pyqtSignal(object)
def __init__(self, parent):
super().__init__(parent)
super(logging.Handler).__init__()
formatter = Formatter('%(asctime)s|%(levelname)s|%(message)s|', '%d/%m/%Y %H:%M:%S')
self.setFormatter(formatter)
def emit(self, record):
msg = self.format(record)
self.new_record.emit(msg) # <---- emit signal here
class Formatter(logging.Formatter):
def formatException(self, ei):
result = super(Formatter, self).formatException(ei)
return result
def format(self, record):
s = super(Formatter, self).format(record)
if record.exc_text:
s = s.replace('\n', '')
return s
# gui.py
... # GUI code
...
def setup_logger(self)
handler = Handler(self)
log_text_box = QPlainTextEdit(self)
self.main_layout.addWidget(log_text_box)
logging.getLogger().addHandler(handler)
logging.getLogger().setLevel(logging.INFO)
handler.new_record.connect(log_text_box.appendPlainText) # <---- connect QPlainTextEdit.appendPlainText slot
...
On dirait que vous voudrez utiliser un widget QPlainTextEdit réglé en lecture seule.
Pensez à changer la couleur d'arrière-plan en gris pour donner à l'utilisateur une indication qu'elle n'est pas modifiable. C'est aussi à vous de décider si vous souhaitez le faire défiler ou sélectionner le texte.
Cette réponse peut vous aider à commencer à sous-classer QPlainTextEdit pour faire défiler avec la sortie, enregistrer dans un fichier, peu importe.