2013-04-04 24 views
10

私は大部分が技術に精通した人のための小さなツールを書いています。プログラマー、エンジニアなどがあります。これらのツールは、通常、時間の経過とともに改良された高速ハックであるため、処理されない例外が発生する可能性があり、ユーザーは気にしません。ユーザーに私にトレースバックを送って何が起こったのかを調べて、アプリケーションを改善できるようにしたい。GUIで未処理の例外を処理する

私は通常wxPythonプログラミングを行いますが、私は最近いくつかのJavaを行っています。私はクラスをThread.UncaughtExceptionHandler()に繋ぎました。私はその結果にとても満足しています。特に、それがどのスレッドからの例外をキャッチして処理できること:

enter image description here

enter image description here

を私は長い時間のためにwxPythonの中に似た何かをやっていました。しかし、

  1. 私は別のスレッドから例外をうまく印刷できるようにするためにデコレータハックを書く必要がありました。
  2. 機能的であっても、結果はかなり醜いです。ここで

enter image description here

あなたは私が行っているものを見ることができるように、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(); 
    } 

} 

の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のどちらかでより良い方法があるでしょうか?

+0

ありがとうフェニスコ。 :) –

+0

あなたは大歓迎です。私は確かになぜ感謝していない:-)。 – Fenikso

+2

プログラマの問題を考える人はほんのわずかです:) –

答えて

3

sys.execpthookには、キャッチされない例外のために呼び出す関数を設定することができます。次に、デコレータは必要ありません。代わりに、フック関数の中で例外を一括して扱うことができます。

例外トレースバックテキストを印刷してストック標準出力ウィンドウに表示させるのではなく、ダイアログを使用してテキストを表示したり、ユーザーがエラー情報を開発者に返したり、将来のエラーを無視したり、アプリケーションを再起動したりすることができます。

+0

'sys.execpthook'の使用は素晴らしいです。ありがとう!しかし、私はまだ 'wx.lib 'の' @ thread_guard'デコレータが必要です。delayedresult'ワーカースレッド。 'return 1/0'行の代わりに' r = result.get() '行から例外がスローされます。デコレータを使用して元の例外から情報を保存しないと、重要なデバッグ情報が失われます。 – Fenikso

3

Javaでは、TaskDialogが利用できない場合は、hereのようにJOptionPaneを使用できます。 event dispatch thread以外のスレッドでは、を使用して、hereのように呼び出しをラップします。また、Desktop#mail()を呼び出すオプションを追加することを検討してください。

image

+0

私はJavaを使い慣れていないので、おそらく私はそれに従っていないでしょう。 1)私は 'TaskDialog'の代わりに' JOptionPane'を使うことができると私は理解しています。しかし、どのような状況下では、「TaskDialog」は「利用不可能」になりますか?私は私のシステムにインストールして、私は実行可能なJARを作成する予定です。 – Fenikso

+0

2)私は 'EventQueue.invokeLater()'を使うべき別のスレッドでGUIに何かしたいと思っていると私は理解しています。しかし、Thread.setDefaultUncaughtExceptionHandler'を使って未処理の例外を処理するためには、どんなスレッドからも正常に動作するようです。何か不足していますか? TaskDialogs.showException(e); 'を' EventQueue.invokeLater() 'にもラップする必要がありますか? – Fenikso

+0

1)何らかの理由でそれを使用しないという意味で、私は利用可能ではありませんでした。 2)結果として得られる暗黙的なデータ競合は、[latent]のままである可​​能性があります(http://stackoverflow.com/a/13411868/230513)。 EDTが自動的に再起動するため、 'invokeLater()'によって順序付けが行われずにスタックトレースが混乱する可能性があります。 – trashgod