在GUI中处理未处理的异常

Fen*_*kso 10 python java swing wxpython exception

我主要是为精通技术的人编写一个小工具,例如程序员,工程师等.由于这些工具通常会随着时间的推移而快速改进,我知道会有未处理的异常并且用户不会介意.我希望用户能够向我发送回溯,以便我可以检查发生了什么并可能改进应用程序.

我经常做wxPython编程,但最近我做了一些Java.我已经TaskDialog上课了Thread.UncaughtExceptionHandler(),我对结果非常满意.特别是它可以捕获和处理来自任何线程的异常:

在此输入图像描述

在此输入图像描述

我在wxPython中做了类似的事情很长一段时间.然而:

  1. 我不得不写一个装饰器 - 黑客,以便能够很好地打印来自另一个线程的异常.
  2. 即使功能正常,结果也很难看.

在此输入图像描述

这是Java和wxPython的代码,所以你可以看到我做了什么:

Java的:

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.JButton;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import com.ezware.dialog.task.TaskDialogs;

public class SwingExceptionTest {

    private JFrame frame;

    public static void main(String[] args) {

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (ClassNotFoundException e) {
        }
        catch (InstantiationException e) {
        }
        catch (IllegalAccessException e) {
        }
        catch (UnsupportedLookAndFeelException e) {
        }

        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable e) {
                TaskDialogs.showException(e);
            }
        });

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    SwingExceptionTest window = new SwingExceptionTest();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public SwingExceptionTest() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 600, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridBagLayout gridBagLayout = new GridBagLayout();
        gridBagLayout.columnWidths = new int[]{0, 0};
        gridBagLayout.rowHeights = new int[]{0, 0};
        gridBagLayout.columnWeights = new double[]{0.0, Double.MIN_VALUE};
        gridBagLayout.rowWeights = new double[]{0.0, Double.MIN_VALUE};
        frame.getContentPane().setLayout(gridBagLayout);

        JButton btnNewButton = new JButton("Throw!");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                onButton();
            }
        });
        GridBagConstraints gbc_btnNewButton = new GridBagConstraints();
        gbc_btnNewButton.gridx = 0;
        gbc_btnNewButton.gridy = 0;
        frame.getContentPane().add(btnNewButton, gbc_btnNewButton);
    }

    protected void onButton(){
        Thread worker = new Thread() {
            public void run() { 
                throw new RuntimeException("Exception!");
            }
        };
        worker.start();
    }

}
Run Code Online (Sandbox Code Playgroud)

wxPython的:

import StringIO
import sys
import traceback
import wx
from wx.lib.delayedresult import startWorker


def thread_guard(f):
    def thread_guard_wrapper(*args, **kwargs) :
        try:
            r = f(*args, **kwargs)
            return r
        except Exception:
            exc = sys.exc_info()
            output = StringIO.StringIO()
            traceback.print_exception(exc[0], exc[1], exc[2], file=output)
            raise Exception("<THREAD GUARD>\n\n" + output.getvalue())
    return thread_guard_wrapper

@thread_guard
def thread_func():
    return 1 / 0

def thread_done(result):
    r = result.get()
    print r


class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.panel = wx.Panel(self)
        self.button = wx.Button(self.panel, label="Throw!")
        self.button.Bind(wx.EVT_BUTTON, self.OnButton)

        self.sizer = wx.BoxSizer()
        self.sizer.Add(self.button)

        self.panel.SetSizerAndFit(self.sizer)  
        self.Show()

    def OnButton(self, e):
        startWorker(thread_done, thread_func)

app = wx.App(True)
win = MainWindow(None, size=(600, 400))
app.MainLoop()
Run Code Online (Sandbox Code Playgroud)

现在的问题是:

我可以在wxPython中轻松完成与Java解决方案类似的操作吗?或许,在Java或wxPython中有更好的方法吗?

Rob*_*unn 3

在 Python 中,您可以设置sys.execpthook一个要为未捕获的异常调用的函数。那么你就不需要装饰器了,你可以在你的钩子函数中集中处理异常。

不仅仅是打印异常回溯文本并让它显示在库存标准输出窗口中,您还可以用它做一些更智能的事情,例如使用对话框来显示文本并具有允许用户将错误信息发送回的控件开发人员,忽略未来的错误,重新启动应用程序,或任何你想要的。