在GUI中处理未处理的异常

时间:2013-04-04 14:42:45

标签: java python swing exception wxpython

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

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

enter image description here

enter image description here

我在wxPython中做了类似的事情很长一段时间。但是:

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

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

    爪哇:

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

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

    现在的问题是:

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

2 个答案:

答案 0 :(得分:3)

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

而不是仅打印异常回溯文本并让它显示在stock stdout窗口中,您可以使用它做一些更智能的操作,比如使用对话框显示文本并具有允许用户发送错误的控件将信息反馈给开发人员,忽略未来错误,重新启动应用程序或任何您想要的信息。

答案 1 :(得分:3)

在Java中,如果TaskDialog不可用,您可以使用JOptionPane,如图here所示。在event dispatch thread以外的其他帖子中,按照建议here使用EventQueue.invokeLater()打包电话。另请考虑添加可选配置以调用Desktop#mail()

image

相关问题