Обработка необработанного исключения в графическом интерфейсе

В основном я пишу небольшие инструменты для тех, кто разбирается в технологиях, например, для программистов, инженеров и т. Д. Поскольку эти инструменты обычно быстро улучшаются, со временем я знаю, что будут необработанные исключения, и пользователи не будут возражать. Я хотел бы, чтобы пользователь мог отправить мне трассировку, чтобы я мог изучить то, что произошло, и, возможно, улучшить приложение.

Я обычно занимаюсь программированием на wxPython, но недавно я немного поработал над Java. Я подключил TaskDialogкласс кThread.UncaughtExceptionHandler()и я вполне доволен результатом. Тем более что он может ловить и обрабатывать исключения из любого потока:

Я делал нечто подобное в wxPython в течение длительного времени. Тем не мение:

  1. Я должен был написать хакер-декоратор, чтобы хорошо печатать исключения из другого потока.
  2. Даже когда он функционален, результат довольно уродливый.

Вот код для 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()

Теперь вопрос:

Могу ли я легко сделать что-то похожее на решение Java в wxPython?Или, может быть, есть ли лучший способ в Java или wxPython?

2 ответа

Решение

В Python вы можете установить sys.execpthook к функции, которую вы хотите вызывать для необработанных исключений. Тогда вам не понадобятся декораторы, вместо этого вы можете просто централизованно обрабатывать исключения.

И вместо того, чтобы просто печатать текст трассировки исключений и отображать его в окне стандартного вывода, вы можете сделать что-то более интеллектуальное с ним, например, использовать диалоговое окно для отображения текста и иметь элементы управления, которые позволяют пользователю отправлять информацию об ошибке обратно разработчик, чтобы игнорировать будущие ошибки, перезапустить приложение, или все, что вы хотите.

В Java, если TaskDialog недоступен, вы можете использовать JOptionPane, как показано здесь. Из потока, отличного от потока диспетчеризации событий, оберните вызов, используя EventQueue.invokeLater(), как предлагается здесь. Также рассмотрите возможность добавления дополнительного положения для вызова Desktop#mail(),

образ

Другие вопросы по тегам