MessageBoxを表示する
「※どうしてもスクリプトがうまく動かない時」で紹介しているErrorCheck.pyを改造してエラー表示をWindowsでお馴染みのMessageBoxで表示するようにしてみたいと思います。スタートはErrorCheck.pyから
ErrorCheck.pyの中身は次の通りです。# coding: shift-jis
import sys
import traceback
try:
import badhello ←テストターゲットのスクリプトは"badhello.py"
except:
traceback.print_exc() ←エラーを表示させている行
raw_input()
簡単ですね。エラーが起きるかどうかtry〜except文で評価して、エラーが起きたらtrace.backモジュールの関数を使ってエラーを表示しなさいというものです。
traceback.print_exc()
↓
ex = traceback.format_exc()
print ex
print_exc()関数の役割を2つに分けるとformat_exc()関数とprint文になります。format_exc()関数はエラー表示の文字列を返して、文字列exに保存し、
print文で画面表示させます。このprint文の代わりに、MessageBoxを使います。
MessageBoxはSystem.Windows.Formsの中にありますので、まずはSystem.Windows.Formsを使えるようにします。
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import * ←いろいろなオブジェクトを抜き出す
次にprint文の箇所をMessageBoxに変更します。MessageBox.Show(ex,"エラー",MessageBoxButtons.OK,MessageBoxIcon.Error)
MessageBoxから始まる部分は全部System.Windows.Formsから抜き出した物です。スクリプトErrorCheck2.pyの全体を表示するとこんな感じ
# coding: shift-jis
import sys
import traceback
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import *
try:
import badhello
except:
ex = traceback.format_exc()
MessageBox.Show(ex, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)

こんなのが出れば成功です。
MessageBoxのオーナーを決める
次のようなスクリプトファイルbadhello2.pyがあったとします。# coding: shift-jis
print "あなたの名前を教えてください。"
name = raw_input()
print "Hello, "+ name + "!"
print 1.0/0
raw_input()
これを先程作ったErrorCheck2.pyでimportして試してみると、確かにエラーが出るのですが、MessageBoxが入力しているWindowの後ろに行ってしまいます。普通エラーWindowは一番前に来なければいけません。MicroSoftのホームページでは、MessageBoxについて次のように書かれています。
MessageBox.Show メソッド (IWin32Window, String, String, MessageBoxButtons)
指定したオブジェクトの前に、指定したテキスト、キャプション、およびボタンを表示するメッセージ ボックスを表示します。
指定したオブジェクトの前に、指定したテキスト、キャプション、およびボタンを表示するメッセージ ボックスを表示します。
ということでIWin32Windowを指定すれば良いことが分かります。ではIWin32Windowとは何かというと
IWin32Window インターフェイス
Win32 HWND ハンドルを公開するためのインターフェイスを提供します。
Win32 HWND ハンドルを公開するためのインターフェイスを提供します。
ということなので、現在のProcessのWindowハンドルを入手して、IWin32Windowのプロパティに代入すると次のようになります。
# coding: shift-jis
import sys
import traceback
from System.Diagnostics import * ←Processクラスを使用するため
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import *
#IWin32Windowを継承したサブクラスを作る
class WinWrapper(IWin32Window):
def __init__(self, oHandle):
self.oHand = oHandle
def get_Handle(self):
return self.oHand
proc = Process.GetCurrentProcess()
oParentHandle = WinWrapper(proc.MainWindowHandle)
try:
import badhello2
except:
ex = traceback.format_exc()
MessageBox.Show(oParentHandle, ex,
"エラー",MessageBoxButtons.OK,MessageBoxIcon.Error)
スクリプトにも書いたように次の今回のポイントはIWin32Windowを継承するところにあります。class WinWrapper(IWin32Window):
def __init__(self, oHandle):
self.oHand = oHandle
def get_Handle(self):
return self.oHand
そもそもインタフェースっているのは何かというと、例えばクラスを人に例えて、あなたのお父さんだとします。あなたのお父さんは、あなたという"子供"のプロパティを持っています。と同時にあなたのお父さんには"親"というプロパティも持っています。これはあなたのお父さんを"家系"という見方で見た場合です。"社会人"という見方で見れば勤めている"会社"があるわけで、"給料"というプロパティと"地位"というプロパティがあります。また"健康診断"という見方であれば"身長","体重","視力","血圧"などの見方があります。同じ"あなたのお父さん"と人物であるのですが、いろいろな見方が存在し、それにより当然あるべきプロパティというものが出てきます。この"見方"のことをインターフェースと呼びます。
つまり、あるクラスがIWin32Windowというインターフェースを持っているということは、IWin32Windowという見方をして良いことを示しています。ここでIWin32Windowという見方ができるということは、Handleというプロパティを持っていることが条件です。
そこでIWin32Windowを継承するWinWrapperにはHandleプロパティを受け渡す仕組みを作る必要があります。具体的にはget_Handle(self)を定義すれば良いです。
★Handleを受け渡す記述の仕方はプログラム言語によって異なるようです。Microsoftの記述を見る限りでは、Iron PythonはJ#と同じように記載すれば良いようです。さすがJythonの作者と同じって感じですね。
Python2.6らしく作ってみよう
上の記述は、IronPython2.0でも対応できます。IronPython2.6以降ではPython2.6と互換をもっているので、Handleプロパティの記述を"@property"や"@property.setter"を使ってやってみました。# coding: shift-jis
import sys
import traceback
from System.Diagnostics import *
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import *
class WinWrapper(IWin32Window):
@property ←プロパティという記述が使えます。
def Handle(self):
return self._Handle
@Handle.setter ←プロパティ設定用関数であることを示している。
def Handle(self, value):
self._Handle = value
proc = Process.GetCurrentProcess()
oParentHandle = WinWrapper() ←初期値ではHandleを設定しない。
oParentHandle.Handle = proc.MainWindowHandle ←プロパティの代入で設定
try:
import badhello2
except:
ex = traceback.format_exc()
MessageBox.Show(oParentHandle, ex,"エラー",MessageBoxButtons.OK,
MessageBoxIcon.Error)
上記が一番IronPythonらしい表現だと思います。ではでは。