2016-07-19 4 views
1

Ich habe mehrere Python-Programme für andere entwickelt, die Tkinter verwenden, um Eingaben vom Benutzer zu erhalten. Um die Dinge einfach und benutzerfreundlich zu halten, werden die Befehlszeilen- oder Python-Konsole nie aufgerufen (dh .pyw-Dateien werden verwendet), daher untersuche ich die Protokollierungsbibliothek, um Fehlertext in eine Datei zu schreiben, wenn ein Ausnahme tritt auf. Allerdings habe ich Schwierigkeiten, die Ausnahmen zu erfassen. Zum Beispiel:Speichern von Ausnahmen in Tkinter mit Python

Wir schreiben eine Funktion, die einen Fehler verursachen wird:

def cause_an_error(): 
    a = 3/0 

Jetzt versuchen wir den Fehler zu protokollieren normalerweise:

import logging 
logging.basicConfig(filename='errors.log', level=logging.ERROR) 

try: 
    cause_an_error() 
except: 
    logging.exception('simple-exception') 

Wie erwartet, werden die Programmfehler und Protokollierung schreibt der Fehler zu errors.log. In der Konsole wird nichts angezeigt. Allerdings gibt es ein anderes Ergebnis, wenn wir eine Tkinter-Schnittstelle implementieren, etwa so:

import logging 
import Tkinter 
logging.basicConfig(filename='errors.log', level=logging.ERROR) 

try: 
    root = Tkinter.Tk() 
    Tkinter.Button(root, text='Test', command=cause_an_error).pack() 
    root.mainloop() 
except: 
    logging.exception('simple-exception') 

In diesem Fall wird die Schaltfläche im Fenster Tkinter Drücken bewirkt, dass der Fehler. Doch dieses Mal wird nichts in die Datei geschrieben, und der folgende Fehler wird in der Konsole:

Exception in Tkinter callback 
Traceback (most recent call last): 
    File "C:\Python27\lib\lib-tk\Tkinter.py", line 1536, in __call__ 
    return self.func(*args) 
    File "C:/Users/samk/Documents/GitHub/sandbox/sandbox2.pyw", line 8, in cause_an_error 
    a = 3/0 
ZeroDivisionError: integer division or modulo by zero 

Gibt es eine andere Art und Weise und melden diese Fehler zu fangen?

+0

Tkinter läuft auf einem eigenen Thread, und alles, was nach dem 'root.mainloop' kommt nur dann ausgeführt wird, nachdem du schließt das Fenster. Beachten Sie auch, dass 'cause_an_error' nur ausgeführt wird, wenn Sie auf die Schaltfläche klicken, aber zuerst' root.mainloop' ausgeführt wird. Was wahrscheinlich passiert, ist, dass die Ausnahme nicht erwischt wird, weil sie in eine andere "Umgebung" geworfen wird ... Ich hoffe, dass jemand eine detailliertere und technische Antwort hat. – nbro

+0

Interessant. Jetzt, wo Sie es erwähnen, kann der Befehl 'raise' den Fehler ebenfalls nicht finden, so dass er definitiv in eine andere Umgebung geworfen wird. Gibt es eine Möglichkeit, die Fehlerbehandlung von Tkinter zu modifizieren, um die Protokollierung nach dem Import einzuschließen? –

+0

Durch Sie könnte die Ausnahme in der Funktion direkt abfangen ... – nbro

Antwort

2

Es ist nicht sehr gut dokumentiert, aber tkinter ruft eine Methode für Ausnahmen auf, die als Ergebnis eines Callbacks auftreten. Sie können Ihre eigene Methode schreiben, um zu tun, was Sie wollen, indem Sie das Attribut report_callback_exception im Root-Fenster setzen.

Zum Beispiel:

import tkinter as tk 

def handle_exception(exception, value, traceback): 
    print("Caught exception:", exception) 

def raise_error(): 
    raise Exception("Sad trombone!") 

root = tk.Tk() 
# setup custom exception handling 
root.report_callback_exception=handle_exception 

# create button that causes exception 
b = tk.Button(root, text="Generate Exception", command=raise_error) 
b.pack(padx=20, pady=20) 

root.mainloop() 

Zum Vergleich:

+0

Perfekt, danke! :) Gibt es eine Möglichkeit, die Zeilennummer oder die Funktion, die die Ausnahme erzeugt hat, abzurufen? –

+1

@SamKrygsheld: Sehen Sie sich das Argument 'traceback' an. –

+0

Ah ja, danke. Für jeden, der das in Zukunft sehen könnte, hatte ich angenommen, dass das Traceback, das übergeben wurde, eine Zeichenkette war, aber es ist tatsächlich ein Traceback-Objekt. Mit traceback.tb_lineno können Sie auf die Zeilennummer zugreifen. –