Description: I have written a custom log handler for capturing log events and writing them to a QTextBrowser object (working sample code shown below).
Here is another method. In this example, I add a StreamHandler
to the logger that writes to a buffer by inheriting from both QObject
and StringIO
: When the handler encounters a non-empty string, the bufferMessage
signal is emitted and captured in the on_bufferMessage
slot.
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import logging, StringIO, time
from PyQt4 import QtCore, QtGui
class logBuffer(QtCore.QObject, StringIO.StringIO):
bufferMessage = QtCore.pyqtSignal(str)
def __init__(self, *args, **kwargs):
QtCore.QObject.__init__(self)
StringIO.StringIO.__init__(self, *args, **kwargs)
def write(self, message):
if message:
self.bufferMessage.emit(unicode(message))
StringIO.StringIO.write(self, message)
class myThread(QtCore.QThread):
def __init__(self, parent=None):
super(myThread, self).__init__(parent)
self.iteration = None
def start(self):
self.iteration = 3
return super(myThread, self).start()
def run(self):
while self.iteration:
logging.info("Hello from thread {0}! {1}".format(0, self.iteration))
self.iteration -= 1
time.sleep(3)
class myThread1(QtCore.QThread):
def __init__(self, parent=None):
super(myThread1, self).__init__(parent)
self.iteration = None
self.logger = logging.getLogger(__name__)
def start(self):
self.iteration = 3
return super(myThread1, self).start()
def run(self):
time.sleep(1)
while self.iteration:
self.logger.info("Hello from thread {0}! {1}".format(1, self.iteration))
self.iteration -= 1
time.sleep(3)
class myWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.pushButton = QtGui.QPushButton(self)
self.pushButton.setText("Send Log Message")
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.pushButtonThread = QtGui.QPushButton(self)
self.pushButtonThread.setText("Start Threading")
self.pushButtonThread.clicked.connect(self.on_pushButtonThread_clicked)
self.lineEdit = QtGui.QLineEdit(self)
self.lineEdit.setText("Hello!")
self.label = QtGui.QLabel(self)
self.layout = QtGui.QVBoxLayout(self)
self.layout.addWidget(self.lineEdit)
self.layout.addWidget(self.pushButton)
self.layout.addWidget(self.pushButtonThread)
self.layout.addWidget(self.label)
self.logBuffer = logBuffer()
self.logBuffer.bufferMessage.connect(self.on_logBuffer_bufferMessage)
logFormatter = logging.Formatter('%(levelname)s: %(message)s')
logHandler = logging.StreamHandler(self.logBuffer)
logHandler.setFormatter(logFormatter)
self.logger = logging.getLogger()
self.logger.setLevel(logging.INFO)
self.logger.addHandler(logHandler)
self.thread = myThread(self)
self.thread1 = myThread1(self)
@QtCore.pyqtSlot()
def on_pushButtonThread_clicked(self):
self.thread.start()
self.thread1.start()
@QtCore.pyqtSlot(str)
def on_logBuffer_bufferMessage(self, message):
self.label.setText(message)
@QtCore.pyqtSlot()
def on_pushButton_clicked(self):
message = self.lineEdit.text()
self.logger.info(message if message else "No new messages")
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('myWindow')
main = myWindow()
main.show()
sys.exit(app.exec_())
The best thing about this method is that you can log messages from modules/threads of you main app without having to keep any reference to the logger, for example, by calling logging.log(logging.INFO, logging_message)
or logging.info(logging_message)