Еще нужно, чтобы всплывающее окно было скрыто до тех пор, пока оно не понадобится, а затем сделало его видимым.

я запускаю следующий код из терминала, я получаю полезное сообщение об ошибке в терминале:

import Tkinter as tk

master = tk.Tk()

def callback():
    raise UserWarning("Exception!")

b = tk.Button(master, text="This will raise an exception", command=callback)
b.pack()

tk.mainloop()

Однако, если я запускаю его без терминала (скажем, дважды щелкнув по значку), сообщение об ошибке подавляется.

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

Как мне справиться с этим? Есть ли стандартный способ выставлять трассировки, stderror или еще что-то в приложении Tkinter? Я ищу что-то более элегантное, чем ставить попробовать / кроме везде.

РЕДАКТИРОВАТЬ: Йохен Ритцель дал отличный ответ ниже, который выскакивает окно с предупреждением, и упомянул присоединение его к классу. Просто чтобы сделать это явным:

import Tkinter as tk
import traceback, tkMessageBox

class App:
    def __init__(self, master):
        master.report_callback_exception = self.report_callback_exception
        self.frame = tk.Frame(master)
        self.frame.pack()
        b = tk.Button(
            self.frame, text="This will cause an exception",
            command=self.cause_exception)
        b.pack()

    def cause_exception(self):
        a = []
        a.a = 0 #A traceback makes this easy to catch and fix

    def report_callback_exception(self, *args):
        err = traceback.format_exception(*args)
        tkMessageBox.showerror('Exception', err)

root = tk.Tk()
app = App(root)
root.mainloop()

Мое остающееся замешательство: Йохен упоминает о возможности использования разных функций отчетов об исключениях в разных рамках. Я пока не вижу, как это сделать. Это очевидно?

 Falmarri22 янв. 2011 г., 23:22
Исключение по-прежнему выводится при двойном щелчке на значке. Просто вы нигде не печатаете стандарт.
 Andrew22 янв. 2011 г., 23:29
Согласовано! Я ищу людей, которые рекомендуют элегантный / стандартный способ предоставления пользователю stdout или stderror.
 Don Kirkby24 авг. 2015 г., 20:42
КлассApp это кадр, обычно получаемый изtk.Frame, Если в вашей программе было два разных класса фреймов, которые использовались для разных целей, тогда каждый класс фреймов мог иметь свою собственную версиюreport_callback_exception() это отображает ошибку по-другому.

Ответы на вопрос(2)

Трекер CPython дляtkinter.Tk.report_callback_exception Документация ясно дала понять, чтоРешение Йохена предназначен. Патч также (и в первую очередь) остановил tk от сбоя при исключениях обратного вызова при запуске под pythonw в Windows.

Второе: вот голое начало решения для созданияstderr функция без консоли (это действительно должен быть отдельный вопрос SO).

import sys, tkinter

root = tkinter.Tk()

class Stderr(tkinter.Toplevel):
    def __init__(self):
        self.txt = tkinter.Text(root)
        self.txt.pack()
    def write(self, s):
        self.txt.insert('insert', s)

sys.stderr = Stderr()

1/0 # traceback appears in window

Еще нужно, чтобы всплывающее окно было скрыто до тех пор, пока оно не понадобится, а затем сделало его видимым.

Решение Вопроса

Естьreport_callback_exception сделать это:

import traceback
import tkMessageBox

# You would normally put that on the App class
def show_error(self, *args):
    err = traceback.format_exception(*args)
    tkMessageBox.showerror('Exception',err)
# but this works too
tk.Tk.report_callback_exception = show_error

Если вы не импортировали «Tkinter as tk», выполните

Tkinter.Tk.report_callback_exception = show_error
 Andrew23 янв. 2011 г., 00:06
Отлично, спасибо! Не могли бы вы расширить свой комментарий о размещении этого в классе App?
 Steven M. Vascellaro01 мар. 2018 г., 20:01
 Stanislav Ivanov11 окт. 2018 г., 11:00
Также работает в python3, но вам нужно использоватьmessagebox изtkinter модуль вместоtkMessageBox.
 Jochen Ritzel23 янв. 2011 г., 00:13
@Andrew: я просто имел в виду, что обычно вы пишете свое приложение в подклассе, который переписывает этот метод, вместо того, чтобы изменять сам класс Tk. На всякий случай, если вам нужны разные функции отчета в разных кадрах.
 Steven M. Vascellaro01 мар. 2018 г., 21:40
Если у вас есть класс приложения дляTk, вы можете переопределить функцию обработки ошибок с помощьюdef report_callback_exception(self, exc, val, tb): tkMessageBox.showerror("Exception", message=str(val))

Ваш ответ на вопрос