tkinter python: перехват исключений

Начав программировать на Python, я чувствовал себя как дома с его сообщениями об ошибках. Теперь, когда вместо этого я программирую с помощью Tkinter, я обнаружил, что часто случается, что в моей программе есть ошибки, которые я не замечаю, даже если они генерируют исключение: я ловлю их (иногда) только потому, что я отлаживаю шаг за шагом Шаг (я использую wingIDE) и, например. в данной строке я вижу сообщение об исключении. Но что меня раздражает, так это то, что программа не останавливается, хотя это происходит даже в блоках не внутри try/error.

Если то, что я сказал, имеет какой-то смысл, знаете ли вы о каком-то общем подходе, по крайней мере, для отображения ошибок? Находясь в Tkinter, я мог создать окно ошибки и заполнить его любым возникающим исключением, когда это произойдет.


person alessandro    schedule 12.07.2011    source источник
comment
есть элегантное решение: stackoverflow.com/questions/4770993/   -  person Gonzo    schedule 24.07.2012
comment
Возможный дубликат Должен ли я сделать тихие исключения громче в tkinter?   -  person Stevoisiak    schedule 01.03.2018


Ответы (3)


См. ответы на Как сделать тихие исключения громче в tkinter, которые показывают, как подключить обратный вызов к tkinter.Tk.report_callback_exception.

person Steven Rumbalski    schedule 12.07.2011
comment
спасибо за вашу помощь, я могу более или менее заставить это работать. Но я не знаком (программист-новичок на python) с синтаксисом @safe, поэтому я не знаю точно, где его поместить в свой код... мне кажется, что я должен поставить @safe перед каждым определением функции, которое должно смотреть... так ли это? - person alessandro; 13.07.2011
comment
@алессандро: ты прав. Их называют декораторами. Декораторы — это синтаксический сахар для вызова классов и функций, которые могут оборачивать другие функции. - person Steven Rumbalski; 13.07.2011
comment
@StevenRumbalski Я намеренно оставил импорт без изменений. Я вносил только те изменения, которые были обратно совместимы с Python 2. - person Stevoisiak; 01.03.2018
comment
@StevenRumbalski Я думал, что печать совместима с переадресацией без импорта будущего? - person Stevoisiak; 01.03.2018
comment
@StevenVascellaro: без будущего импорта print 3 и print(3) одинаковы, но print 1, 2, 3 и print(1, 2, 3) имеют выходы 1 2 3 и (1, 2, 3) соответственно. И выполнение print(1, end='') является синтаксической ошибкой. Один аргумент не проблема, потому что круглые скобки можно просто проигнорировать. Несколько аргументов становятся кортежем, потому что запятые. Я думаю, что именованные аргументы являются проблемой, потому что Python уже решил, что print является оператором, и поэтому он даже не пытается рассматривать его как функцию. - person Steven Rumbalski; 01.03.2018

Как сказал @jochen-ritzel (Должен ли я сделать тихие исключения громче в tkinter?), есть tk.TK.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
person ankostis    schedule 14.10.2014

Я предпочитаю явное расширение виджета Toplevel Tk, который представляет в основном главное окно приложения, а не внедрение хака:

import tkinter as tk
from tkinter import messagebox

class FaultTolerantTk(tk.Tk):
    def report_callback_exception(self, exc, val, tb):
        self.destroy_unmapped_children(self)
        messagebox.showerror('Error!', val)

    # NOTE: It's an optional method. Add one if you have multiple windows to open
    def destroy_unmapped_children(self, parent):
        """
        Destroys unmapped windows (empty gray ones which got an error during initialization)
        recursively from bottom (root window) to top (last opened window).
        """
        children = parent.children.copy()
        for index, child in children.items():
            if not child.winfo_ismapped():
                parent.children.pop(index).destroy()
            else:
                self.destroy_unmapped_children(child)

def main():
    root = FaultTolerantTk()
    ...
    root.mainloop()


if __name__ == '__main__':
    main()

ИМХО это выглядит как правильный путь.

person Yurii Rabeshko    schedule 23.10.2018