Logging output in QT GUI

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Poseidonius
User
Beiträge: 63
Registriert: Montag 23. Januar 2006, 08:58

Hallo zusammen,

ich möchte die Ausgaben des Logging Moduls statt in die Konsole in einem QtTextEdit Feld anzeigen lassen. Wie muss ich den StreamHandler umbiegen? Hat jemand einen Beispiellink für mich?

Tausend Dank und ein schönes Wochenende

Poseidonius
lunar

Ist es nicht einfacher, einen neuen Handler zu schreiben?
Xinor
User
Beiträge: 13
Registriert: Montag 31. Mai 2010, 11:51

Poseidonius
User
Beiträge: 63
Registriert: Montag 23. Januar 2006, 08:58

Ja, genau so was !!!

Danke
lunar

@Poseidonius: Irgendwie habe ich das Gefühl, dass Du von München aus über Moskau nach Berlin zu reisen versuchst ;)
Poseidonius
User
Beiträge: 63
Registriert: Montag 23. Januar 2006, 08:58

langsam glaube ich Du hast Recht lunar :-)

Aber wie kann ich einen eigene Handlerklasse in der Konfiguration des Logging statt des StreamHandler() unterbringen?

Code: Alles auswählen

import logging

# create logger
logger = logging.getLogger("simple_example")
logger.setLevel(logging.DEBUG)

# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
Helft mir bitte auf die Sprünge

Danke
Poseidonius
User
Beiträge: 63
Registriert: Montag 23. Januar 2006, 08:58

Hallo zusammen,

glücklich ist der, der Doku lesen kann :-)
Falls noch mal jemand ein ähnliches Problem haben sollte, könnte man das Logging nach Qt so angehen:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import logging
from PyQt4 import QtCore, QtGui

class Ui_Dialog(object, logging.Handler):
  def __init__(self):
    logging.Handler.__init__(self)
    
  def setupUi(self, Dialog):
    self.textEdit = QtGui.QTextEdit(Dialog)
    self.textEdit.setGeometry(QtCore.QRect(15, 15, 600, 200))

  def emit(self, string):
    self.textEdit.append(self.format(string))

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Dialog = QtGui.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
                 
    logger = logging.getLogger("GUI")
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",'%H:%M:%S')
    ui.setFormatter(formatter)

    logger.addHandler(ui)
    logger.setLevel(logging.DEBUG)

    logger.debug("DEBUG")
    logger.warning('WARNING')
    logger.info("INFO")
    
    sys.exit(app.exec_())
Grüße und Danke für die Hinweise
lunar

Schön ist diese Lösung allerdings nicht.
Poseidonius
User
Beiträge: 63
Registriert: Montag 23. Januar 2006, 08:58

Hallo lunar,

welche Sachen gefallen Dir nicht, sprich wo sollte ich nachbessern?

Grüße und vielen Dank für Deine Geduld

Poseidonius
lunar

So ziemlich alles. Grundsätzlich solltest Du PEP 8 beachten, vor allem im Hinblick auf Groß- und Kleinschreibung von Namen. Das "Dialog"-Argument für "Ui_Dialog.setupUi" beispielsweise ist keine Klasse, sondern ein Exemplar und sollte demnach klein geschrieben werden. Zudem solltest Du vernünftige und korrekte Namen vergeben. "Ui_Dialog" ist beispielsweise vollkommen irreführend, denn diese Klasse ist kein Dialog (und auch nicht automatisch generiert, worauf das "Ui_"-Präfix hindeutet), sondern ein Logging-Handler. Ähnliches gilt für das "string"-Argument für "Ui_Dialog.emit". Das ist keine Zeichenkette, sondern ein Log-Eintrag vom Typ "LogRecord".

Ferner nutzt man keine festen Größenangaben für graphische Steuerelemente, ".setGeometry"-Aufruf mit Konstanten haben in gutem Quelltext nichts zu suchen. Zudem enthält Dein Beispiel überflüssigen Quelltext, wie die unnötige Mehrfachvererbung bei Ui_Dialog ("logging.Handler" reicht), und die "Ui_Dialog.__init__()"-Methode, die nichts tut, als einfach an die Vaterklasse zu delegieren.

Vor allem aber ist Ui_Dialog nicht sauber gekapselt. Der Handler sollte das Steuerelement nicht selbst irgendwie irgendwo erzeugen, sondern vielmehr von außen übergeben bekommen. So wäre es richtig:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import logging

from PyQt4.QtGui import QApplication, QMainWindow, QTextEdit

class QTextEditLoggingHandler(logging.Handler):
  def __init__(self, text_edit):
    logging.Handler.__init__(self)
    self.text_edit = text_edit

  def emit(self, record):
    self.text_edit.append(self.format(record))


def main():
    import sys
    app = QApplication(sys.argv)
    mainwindow = QMainWindow()
    textedit = QTextEdit(mainwindow)
    mainwindow.setCentralWidget(textedit)
    mainwindow.show()

    logger = logging.getLogger("GUI")
    handler = QTextEditLoggingHandler(textedit)
    handler.setFormatter(
        logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",'%H:%M:%S'))
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)

    logger.debug("DEBUG")
    logger.warning('WARNING')
    logger.info("INFO")

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
passe.partout
User
Beiträge: 11
Registriert: Donnerstag 9. September 2010, 10:33

Also ich finde die ursprüngliche Lösung besser, da sie nicht so steril ist. Des Weiteren ist es kein guter Stil eine vorhandene Lösung, die man selbst nicht erdacht hatte, nur in der Form zu verbessern, dabei handelt es sich nicht um eine Lösungsfindung sondern um banalen Spam...
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

passe.partout hat geschrieben:Also ich finde die ursprüngliche Lösung besser, da sie nicht so steril ist.
Definiere "steril"? Im übrigen hat lunar gute Gründe aufgezeigt, die eben schlecht waren an dieser Lösung
Des Weiteren ist es kein guter Stil eine vorhandene Lösung, die man selbst nicht erdacht hatte, nur in der Form zu verbessern, dabei handelt es sich nicht um eine Lösungsfindung sondern um banalen Spam...
Desweiteren ist es kein guter Stil, hier bereits im ersten Posting jemanden einen schlechten Stil zu unterstellen, der hier im Forum und speziell bei PyQt einer der kompetentesten Poster ist ;-)

Außerdem ist Deine Aussage schlicht dumm: Es geht bei einer Lösung nicht nur um die Quantisierung in "läuft" und "läuft nicht". Es gibt auch Dinge wie "idiomatisch gut", "schöner lesbar", "schneller", "kompakter", usw. Insofern zeigt lunar zunächst auf, was ihm nicht gefällt und präsentiert dann eine von ihm verbesserte Version. Was sollte daran "spamming" sein? Ganz im Gegenteil ist das didaktisch wunderbar :-)

Und selbst wenn es dem OP egal sein sollte, lesen hier ja auch andere Leute mit und die lernen dadurch ja auch etwas. Diesen Aspekt bitte nie vergessen!

Mit Deiner Einstellung stehst Du hier jedenfalls ziemlich alleine da. Außerdem wundert es mich, wie Du mit solch einer Einstellung überhaupt jemals etwas gelernt hast - sobald etwas funzt, braucht man es nach Deiner Auffasung ja nie wieder abändern oder anfassen... wirklich äußerst dumm und borniert!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lunar

@Hyperion: Hier ist mir jetzt eindeutig zu viel „schlechter Stil“ im Spiel ;)

Im Übrigen glaube ich ja nicht, dass jemand, der sich für einen solchen Beitrag extra anmeldet, je einen weiteren sinnvollen Beitrag verfassen wird. Insofern ab auf die Ignore-Liste damit ... ein wirklich schönes Feature im neuen Board, meine Liste wächst stetig ;)
passe.partout
User
Beiträge: 11
Registriert: Donnerstag 9. September 2010, 10:33

Es gibt auch Dinge wie "idiomatisch gut", "schöner lesbar", "schneller", "kompakter", usw. Insofern zeigt lunar zunächst auf was ihm nicht gefällt und präsentiert dann eine von ihm verbesserte Version. Was sollte daran "spamming" sein? Ganz im Gegenteil ist das didaktisch wunderbar.
Ich weiß jetzt leider nicht, wer der Mann in eurer Beziehung ist? :lol:

Aber egal, didaktisch korrekt wäre es gewesen, eine Lösung, die der Fragende selber finden musste, weil er keine Hilfe bekommen hat, nicht als schlecht abzustempeln. Wer inhaltlich nichts beitragen kann, mäkelt immer an der Form... Denkt mal drüber nach... Und die Güte eines Autors bemisst sich nicht an der Latte seiner Beiträge, sondern an deren Qualität. Nun gut, ich habe mir jetzt leider nicht die anderen Korrekturen des rosa Schweinchens :oops: angesehen, vielleicht sind die ja wirklich besser...
Mit Deiner Einstellung stehst Du hier jedenfalls ziemlich alleine da. Außerdem wundert es mich, wie Du mit solch einer Einstellung überhaupt jemals etwas gelernt hast - sobald etwas funzt, braucht man es nach Deiner Auffasung ja nie wieder abändern oder anfassen... wirklich äußerst dumm und borniert!
ohne Worte ...
BlackJack

@passe.partout: Das Einzige was nur die Form betraf war der Hinweis auf PEP8.

Man darf didaktisch gesehen keine Kritik an etwas üben, was sich jemand selbst erarbeitet hat!? Interessante Ansicht.

Natürlich misst sich die Güte eines Autors nicht daran wieviele Beiträge er verfasst hat -- ich weiss auch gar nicht wie Du darauf kommst!? Hyperion hat von einem kompetenten Poster gesprochen und das nicht an der Anzahl der Beiträge festgemacht.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@passe.partout:
Warum kreierst Du extra einen neuen Account, um das loszuwerden? Für Kritik ist hier jeder offen, solange es um die Sache geht und nicht beleidigend oder unhöflich wird (das rosa Schweinchen hat auch einen Namen)
Poseidonius
User
Beiträge: 63
Registriert: Montag 23. Januar 2006, 08:58

Neben der Aufregung in diesem Thread wollte ich nur kurz Danke sagen für die Anmerkungen und Korrekturen von lunar hinsichtlich meines Codes. Habe einiges daraus gelernt ...

Grüße und einen schönen Abend noch

Poseidonius
passe.partout
User
Beiträge: 11
Registriert: Donnerstag 9. September 2010, 10:33

Hi Poseidonius,

zum Thema Spam, ich habe die Lösung von lunar mal aber sowas von überarbeitet:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import logging

from PyQt4.QtGui import QApplication, QTextEdit

class QTextEditLoggingHandler(logging.Handler):
  def __init__(self, text_edit):
    logging.Handler.__init__(self)
    self.text_edit = text_edit

  def emit(self, record):
    self.text_edit.append(self.format(record))


def main():
    import sys
    app = QApplication(sys.argv)
    window = QTextEdit()
    window.show()
    logger = logging.getLogger("GUI")
    handler = QTextEditLoggingHandler(window)
    handler.setFormatter(
        logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",'%H:%M:%S'))
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)

    logger.debug("DEBUG")
    logger.warning('WARNING')
    logger.info("INFO")

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
Man wird auf den ersten Blick zwar kaum einen Unterschied erkennen, aber diese Lösung ist jetzt viel "kürzer" und "eleganter", da QMainWindow() nicht benötigt wird und somit noch zwei Zeilen zusätzlich herausfallen, die zum Verständnis ja eh nichts beitragen...

An alle, können wir jetzt nicht die ursprünglichen Lösungen löschen???

Das war natürlich ironisch...
Mich hat nur gestört, dass es zu solchen Aussagen kommt, wie: "Er hat vielleicht die Atombombe erfunden, aber meine hat diese wunderbaren Beschleunigungsstreifen...". Soviel zum Stil.
Spam, Spam, Spam wahrscheinlich wird sich noch jemand aufregen :lol:

und @jerch: Nein, habe mich nicht nur deswegen angemeldet, aber Spamming ist halt ein generelles Problem, bei dem man sich auch mal trauen muss es offen anzusprechen und nicht weg sehen darf! Ich wundere mich das keiner geschrieben hatte: "Frag Google". :roll: Und misst du nicht mit zweierlei Maß?
BlackJack

@passe.partout: Mich würde mal interessieren wie Du "Spam" definierst!? Das scheint nicht die übliche Bedeutung für Dich zu haben. Ich verstehe Deinen Beitrag jedenfalls nicht.
passe.partout
User
Beiträge: 11
Registriert: Donnerstag 9. September 2010, 10:33

@BlackJack: siehe meinen ersten Beitrag...
Antworten