Wie man nicht-blockierend/real-time-Verhalten von Python-logging-Modul? (Ausgabe PyQt QTextBrowser)

Beschreibung: ich habe geschrieben ein benutzerdefiniertes Protokoll-handler für die capturing-Protokoll-Ereignisse und schreiben Sie einen QTextBrowser Objekt (Arbeits-Beispielcode unten).

Problem: Drücken Sie die Taste ruft someProcess(). Dies schreibt zwei strings an die logger Objekt. Allerdings werden die strings nur angezeigt, nachdem someProcess() gibt.

Frage: Wie bekomme ich den angemeldet strings erscheinen, um in die QTextBrowser Objekt sofort/in Echtzeit? (d.h., sobald ein logger output-Methode wird aufgerufen)

from PyQt4 import QtCore, QtGui
import sys
import time
import logging
logger = logging.getLogger(__name__)

class ConsoleWindowLogHandler(logging.Handler):
    def __init__(self, textBox):
        super(ConsoleWindowLogHandler, self).__init__()
        self.textBox = textBox

    def emit(self, logRecord):
        self.textBox.append(str(logRecord.getMessage()))

def someProcess():
    logger.error("line1")
    time.sleep(5)
    logger.error("line2")

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = QtGui.QWidget()
    textBox = QtGui.QTextBrowser()
    button = QtGui.QPushButton()
    button.clicked.connect(someProcess)
    vertLayout = QtGui.QVBoxLayout()
    vertLayout.addWidget(textBox)
    vertLayout.addWidget(button)
    window.setLayout(vertLayout)
    window.show()
    consoleHandler = ConsoleWindowLogHandler(textBox)
    logger.addHandler(consoleHandler)
    sys.exit(app.exec_())

BEARBEITEN: Dank der Antwort von @abarnert, ich es geschafft, dieses Stück zu schreiben zu arbeiten, code mit QThread. Ich Unterklassen QThread um einige Funktion someProcess in einem hintergrund-thread. Für die Signalisierung, hatte ich Rückgriff auf die old-style-Signals und Slots (ich bin mir nicht sicher, wie es in der new-style). Erstellt habe ich eine dummy QObject, um in der Lage zu emittieren Signale, die von der logging-handler.

from PyQt4 import QtCore, QtGui
import sys
import time
import logging
logger = logging.getLogger(__name__)

#------------------------------------------------------------------------------
class ConsoleWindowLogHandler(logging.Handler):
    def __init__(self, sigEmitter):
        super(ConsoleWindowLogHandler, self).__init__()
        self.sigEmitter = sigEmitter

    def emit(self, logRecord):
        message = str(logRecord.getMessage())
        self.sigEmitter.emit(QtCore.SIGNAL("logMsg(QString)"), message)

#------------------------------------------------------------------------------
class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()

        # Layout
        textBox = QtGui.QTextBrowser()
        self.button = QtGui.QPushButton()
        vertLayout = QtGui.QVBoxLayout()
        vertLayout.addWidget(textBox)
        vertLayout.addWidget(self.button)
        self.setLayout(vertLayout)

        # Connect button
        self.button.clicked.connect(self.buttonPressed)

        # Thread
        self.bee = Worker(self.someProcess, ())
        self.bee.finished.connect(self.restoreUi)
        self.bee.terminated.connect(self.restoreUi)

        # Console handler
        dummyEmitter = QtCore.QObject()
        self.connect(dummyEmitter, QtCore.SIGNAL("logMsg(QString)"),
                     textBox.append)
        consoleHandler = ConsoleWindowLogHandler(dummyEmitter)
        logger.addHandler(consoleHandler)

    def buttonPressed(self):
        self.button.setEnabled(False)
        self.bee.start()

    def someProcess(self):
        logger.error("starting")
        for i in xrange(10):
            logger.error("line%d" % i)
            time.sleep(2)

    def restoreUi(self):
        self.button.setEnabled(True)

#------------------------------------------------------------------------------
class Worker(QtCore.QThread):
    def __init__(self, func, args):
        super(Worker, self).__init__()
        self.func = func
        self.args = args

    def run(self):
        self.func(*self.args)

#------------------------------------------------------------------------------
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
  • Wenn das edit war eine richtige Antwort, es wäre die kanonische Lösung für das gemeinsame problem der Anzeige von log-Meldungen in beiden PyQt und PySide-widgets. Im Gegensatz zu ähnlichen Lösungen, die für alle ähnliche Fragen haben (z.B., dieser, this)Ihre Bearbeiten, nutzt die slots und Signale und damit arbeitet nicht blockingly. Das ist fantastisch.
  • Was weniger toll ist die Verwendung von alten Stil slots und Signale und ein hypetextual QTextBrowser eher als einen nur-lese-Klartext QTextArea. Gebrauch von new-style slots und Signale sollten vermeiden die Notwendigkeit für die dummyEmitter Vermittler. Ebenso, Zitat offizielle QTextBrowser Dokumentation: "Wenn Sie wollen, einen text-browser ohne hypertext-navigation verwenden QTextEdit und verwenden QTextEdit::setReadOnly() zum deaktivieren der Bearbeitung."
InformationsquelleAutor Gilead | 2013-01-16
Schreibe einen Kommentar