Обработка необработанного исключения в графическом интерфейсе
В основном я пишу небольшие инструменты для тех, кто разбирается в технологиях, например, для программистов, инженеров и т. Д. Поскольку эти инструменты обычно быстро улучшаются, со временем я знаю, что будут необработанные исключения, и пользователи не будут возражать. Я хотел бы, чтобы пользователь мог отправить мне трассировку, чтобы я мог изучить то, что произошло, и, возможно, улучшить приложение.
Я обычно занимаюсь программированием на wxPython, но недавно я немного поработал над Java. Я подключил TaskDialog
класс кThread.UncaughtExceptionHandler()
и я вполне доволен результатом. Тем более что он может ловить и обрабатывать исключения из любого потока:
Я делал нечто подобное в wxPython в течение длительного времени. Тем не мение:
- Я должен был написать хакер-декоратор, чтобы хорошо печатать исключения из другого потока.
- Даже когда он функционален, результат довольно уродливый.
Вот код для 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()
,