2016-07-19 2 views
1

Я разработал несколько программ Python для других, которые используют Tkinter для получения ввода от пользователя. Для упрощения и удобства использования командной строки или консоли python никогда не возникают (т. Е. Файлы .pyw), поэтому я изучаю использование библиотеки журналов для записи текста ошибки в файл, когда исключение. Тем не менее, мне трудно получить его, чтобы на самом деле поймать исключения. Например:Сохранение исключений в Tkinter с использованием Python

Напишем функцию, которая будет вызывать ошибку:

def cause_an_error(): 
    a = 3/0 

Теперь мы пытаемся зарегистрировать ошибку обычно:

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

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

Как и ожидалось, программные ошибки и записываются данные ошибка error.log. В консоли ничего не появляется. Однако, есть другой результат, когда мы реализуем интерфейс Tkinter, например так:

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') 

В этом случае, при нажатии кнопки в окне Tkinter вызывает ошибку. Однако, на этот раз, ничего не записывается в файл, и появляется следующее сообщение об ошибке в консоли:

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 

Есть ли другой способ поймать и войти эту ошибку?

+0

Tkinter работает на своем собственном потоке, и все, что приходит после того, как 'root.mainloop' выполняется только после того, как вы закрываете окно. Также обратите внимание, что 'cause_an_error' выполняется только при нажатии кнопки, но сначала выполняется' root.mainloop'. Вероятно, происходит то, что исключение не поймано, потому что его бросают в другую «среду» ... Надеюсь, что кто-то придумает более подробный и технический ответ. – nbro

+0

Интересно. Теперь, когда вы упомянули об этом, команда «raise» также не может получить ошибку, поэтому ее, безусловно, бросают в другую среду. Есть ли способ, с помощью которого я мог бы модифицировать обработку ошибок Tkinter для включения регистрации после импорта? –

+0

Вы можете поймать исключение в функции напрямую ... – nbro

ответ

2

Это не очень хорошо документировано, но tkinter вызывает метод для исключений, которые происходят в результате обратного вызова. Вы можете написать свой собственный метод, чтобы сделать все, что хотите, установив атрибут report_callback_exception в корневое окно.

Например:

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() 

Для справки:

+0

Отлично, спасибо! :) Есть ли способ получить номер строки или функцию, которая создала исключение? –

+1

@SamKrygsheld: посмотрите аргумент 'traceback'. –

+0

Ах да, спасибо. Для всех, кто мог бы это увидеть в будущем, я предположил, что трассировка передается в виде строки, но на самом деле это объект трассировки. Использование traceback.tb_lineno позволит вам получить доступ к номеру строки. –

Смежные вопросы