How to get non-blocking/real-time behavior from Python logging module? (output to PyQt QTextBrowser)

后端 未结 4 1901
清歌不尽
清歌不尽 2020-12-28 22:18

Description: I have written a custom log handler for capturing log events and writing them to a QTextBrowser object (working sample code shown below).

4条回答
  •  礼貌的吻别
    2020-12-28 22:51

    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)

提交回复
热议问题