[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『エラー処理を入れる際のメッセージの使い方』(ピザ男)
エラー処理を入れた際の、
完了メッセージとエラーメッセージを上手いこと二つ入れる方法が
よく分かりません。
現在下記のように作っておりますが
applicationオブジェクトを無駄に同じものを二箇所入れており、
見にくいです。
エラーが起きた時は「エラーが発生しました」(エラーが発生したら続けず直ぐにエラーメッセージを出したい)
完了した際は「完了しました」
とif文のような形で、そのイフが終わった後、
最後にTrueする処理を入れるように
書くことは可能でしょうか?
よろしくお願いいたします。
sub サンプル()
諸々変数宣言
Application.ScreenUpdating = False
Application.DisplayAlerts = False
On Error GoTo ErrLabel
〜諸々処理〜
msgbox "完了しました"
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
ErrLabel:
MsgBox "エラーが発生しました" Application.ScreenUpdating = True Application.DisplayAlerts = True
end sub
< 使用 Excel:Excel2010、使用 OS:Windows10 >
回答ではないです。
私がもし作るのであれば 1)前提として、エラーが出ないように設計する 2)エラーが想定される場合、事前にチェックする 3)それでもエラーが出る場合、デバッグ状態で止まっててもらう(ResumeやGotoをエラートラップとして使わない)
ですかね・・・ 大規模なプログラムの場合は必要でしょうけど、私のような素人が作る程度のものであれば、必要ないです。
提示のコードそのまま直すなら Sub サンプル() 諸々変数宣言 Application.ScreenUpdating = False Application.DisplayAlerts = False On Error GoTo ErrLabel 〜諸々処理〜 ErrLabel: If Err.Number > 0 Then MsgBox "エラーが発生しました" Else MsgBox "完了しました" End If Application.ScreenUpdating = True Application.DisplayAlerts = True End Sub こんな感じですかね・・・
(稲葉) 2019/03/15(金) 08:37
こんにちは。
この書き方はこの書き方でありだと思います エラー処理後、必ずやるべきことをエラー処理ルーチンの中に書くのは、 わかりやすいと思います。
で、
On Error Goto で飛んだエラー処理ルーチンから通常ルーチンに復帰する場合は、 Resume ステートメントを使います。 Resume ステートメントは復帰先をラベルで指定出来るので、以下のように成ります。
Sub サンプル()
Application.ScreenUpdating = False Application.DisplayAlerts = False
On Error GoTo ErrLabel '〜諸々処理〜 Debug.Print 1 / 0 MsgBox "完了しました" On Error GoTo 0
Normal_Terminate: Application.ScreenUpdating = True Application.DisplayAlerts = True Exit Sub
''===============エラー処理ルーチン ============= ErrLabel: MsgBox "エラーが発生しました" Resume Normal_Terminate
End Sub
(でれすけ) 2019/03/15(金) 08:53
でれすけ先生がいらっしゃったので、追加で質問よろしいですか? 「必ずやる処理」が終わった後、デバッグで止めたい場合などは Sub test2() Application.DisplayAlerts = False On Error GoTo ErrLabel Debug.Print 1 / 0 MsgBox "完了しました" ErrLabel: Application.DisplayAlerts = True On Error GoTo 0 If Err.Number > 0 Then Resume: MsgBox "エラーが発生しました" End Sub このように書いても実用でしょうか? (稲葉) 2019/03/15(金) 09:09
こんにちは。
稲葉様 先生はやめてくださいね
で、いろんな書き方の流儀があるので、なんとも...ですが いま稲葉さんの書いたサンプルははっきりと問題があるのでダメです。
×エラー処理ルーチンの中に On Error Goto 0 がある ×Resumeステートメントは、ラベル無しだと、エラー発生行に復帰するのでMsgBoxは実行されない
書こうと思えば、以下の様に書くこともできなくもないですが、 エラー処理ルーチンは、はっきりと正常な処理と分けた方がいいです。 以下のように兼用するのは、 処理の流れがわかりにくい=可読性が悪く、バグの元です。 やっちゃダメです。
On Error に限らず、Goto で処理の流れを吹っ飛ばすのは、 可読性が落ちるので、非推奨です。
VBAでは、実行時エラーのトラップは、On Error Goto しかないので 仕方なく使いますが、なるべくエラー処理ルーチンをはっきり分けた方がいいです。
Sub だめなサンプル()
Application.ScreenUpdating = False Application.DisplayAlerts = False
On Error GoTo ErrLabel '〜諸々処理〜 Debug.Print 1 / 0 MsgBox "完了しました" On Error GoTo 0
ErrLabel: ''=====正常処理ルーチンとエラー処理ルーチン兼用==========
Application.ScreenUpdating = True Application.DisplayAlerts = True
Select Case Err.Number Case 0 Exit Sub 'エラーじゃなかったら終了(正常) Case Else MsgBox "エラーが発生しました" End Select
End Sub
(でれすけ) 2019/03/15(金) 09:51
Sub test21() Dim iEr As Long
Application.DisplayAlerts = False On Error Resume Next Debug.Print 1 / 0 iEr = Err.Number On Error GoTo 0 Application.DisplayAlerts = True
If iEr > 0 Then MsgBox "エラーが発生しました", vbCritical, iEr & " 「" & Error(iEr) & "」" Else MsgBox "完了しました", vbInformation End If End Sub
Sub test22() Dim iEr As Long
Application.DisplayAlerts = False On Error GoTo ErrLabel Debug.Print 1 / 0
sExit: On Error GoTo 0 Application.DisplayAlerts = True
If iEr > 0 Then MsgBox "エラーが発生しました", vbCritical, iEr & " 「" & Error(iEr) & "」" Else MsgBox "完了しました", vbInformation End If Exit Sub
ErrLabel: iEr = Err.Number Resume sExit End Sub (???) 2019/03/15(金) 09:55
でれすけさん ???さん ありがとうございます。 ダメな例がまさに私が最初に書いたコードそのものですね・・ エラーと正常処理ルーチンを別個で持つ理由はわかりましたが、問題の箇所を突き止めるデバッグ状態で 止めたいことを主眼に置いた場合は、そもそもエラー処理ルーチン自体が不要という認識でよろしいでしょうか? >エラーのあった行に Resume してしまうと、VBAによってエラー表示されてしまいます。 逆にVBAによるエラーを吐き出させたいのです。
※先生の件承知しました。 (稲葉) 2019/03/15(金) 10:01
書き忘れ。
On Error で飛ばしたあと、Resumeで復帰させると、処理が2段階でジャンプするので、 処置の流れを追いにくいです。
そうすると、結局、この場合は、ピザ男さんの書き方が可読性の面では一番いいということに。
On Error Resume Next 使うって
Try 〜 Catch 〜 Finally みたいな書き方ができるとすれば、それが一番いいとおもいますが、 なかかうまくいかないですね。
>逆にVBAによるエラーを吐き出させたいのです。 自分でさらにエラーをRaise することも出来ます。
Sub サンプル()
Application.ScreenUpdating = False Application.DisplayAlerts = False
On Error GoTo ErrLabel '〜諸々処理〜 Debug.Print 1 / 0 MsgBox "完了しました" On Error GoTo 0
Application.ScreenUpdating = True Application.DisplayAlerts = True Exit Sub
ErrLabel: ''=====エラー処理ルーチン==========
Application.ScreenUpdating = True Application.DisplayAlerts = True Err.Raise Err.Number, , Err.Description
End Sub
(でれすけ) 2019/03/15(金) 10:07
またまた書き忘れ
自分だけで使うマクロだったら、On Error Goto 使わないです。 デバッグのいい機会なので、ソースを修正するか、 デバックモードで、イミディエイトウィンドウでもじゃもじゃして..実行再開
(でれすけ) 2019/03/15(金) 10:13
エラー番号だけ他の変数に控えて(何なら処理番号とか変数に用意しておき、これも控えるとか)、そのままResumeが良いのではないでしょうか。 エラートラップやコールバック関数内は、処理を止めるような記述は厳禁、という意識があるので、止めたくはないですね。(直接はエラートラップとは関係ないですが、DBのトランザクションを掛けたままエラーメッセージ表示したため、システム全体が止まってしまった、というトラブル例を知ってます)
(???) 2019/03/15(金) 10:24
でれすけさん ???さん 返事遅くなりました。 いろいろご指導ありがとうございました。 > 自分だけで使うマクロだったら、On Error Goto 使わないです。 この部分をどこまで広げるか、で対応が異なってくる気がしました。 私は自分と自分が知りえる範囲でしかマクロを使わないので、On Error Gotoを使ったことがありませんでした。 (こちらにアップするコードもですが)基本的な考え方がわかり、勉強になりました。
>本来の用途としては、エラー原因をトラップ先で対処してから戻す ということは、想定されたエラーであるってことだと思うので、最初から手当してあげれば済むような? とも考えました・・・ エラートラップの本来の使い方ってどうなのでしょう? 想定外のエラーのみが対象ということでいいのでしょうか?
あとは最初と最後の処理を別ルーチンにしてしまうと可読性が落ちるのか、ありなのか?
Sub test3() config False On Error GoTo ErrLabel Debug.Print 1 / 0 On Error GoTo 0 config True MsgBox "完了しました" Exit Sub ErrLabel: config True MsgBox "エラーが発生しました" End Sub Sub config(flg As Boolean) Application.ScreenUpdating = flg Application.DisplayAlerts = flg End Sub
ピザ男さんスレッド借りてしまいすみません。 (稲葉) 2019/03/15(金) 13:27
また、稲葉さんのtest3のように、Application.ScreenUpdating 等をまとめて抑止するような書き方は、抑止自体が過去の言語ではなかったものなので、何が正解というのは無いでしょう。 ただ、全部まとめて共通関数化したコードは他で見たことが無く、可読性は落ちる、と感じました。
とは言っても微妙な話で、いろいろ抑止するという、ロジックの本筋以外を隠すことで、本筋のコードを追いやすくする、という意味では、可読性は上がっていると言えます。 共通化する事でプロジェクト内全てでも関数1つで済む、という利点は判りますし、ちょっとコードを追えば意味も判りますが、誰が見ても一瞬で意味が判るのか?、というところで、可読性が落ちたように感じるのですよ。 可読性を上げるために関数化したのでしょうけど、その関数名が通常のExcelには無いものなので、咄嗟に意味が判らない、という感じ。 まとめてもまとめなくても、どちらもメリット/デメリットがあるなら、ユニーク関数を追加しない、素直な書き方が受け入れられるのでは…、と思いました。
あとは、他人に追わせるコードとして、オブジェクト指向とは真逆なのですが、なるべくサブプロシジャは書きたくない、というのもあります。 1画面の上下だけで読ませたいし、関数コールによる内部のレジスタの退避/復元を無駄と感じるのです。(無駄と言っても所詮はインタプリンタであり、速度的には何の問題も無いのですけどねぇ)
(???) 2019/03/15(金) 14:37
こんにちは。
1. 想定内のエラーは、エラー原因を取り除いて、正常処理に復旧させる 2. 想定外のエラー発生時に突然終了させずに、「最低限必要な処理をしてから」終了させる 3. 例外発生の有無を条件分岐につかっって、コードを簡略化する
想定されてても、事前に対処するのが面倒なときとか、出来ないときとかって結構ありましてね。 特に昔は....
今でもファイル入出力関係とかではよくあると思いますよ。 書き込み途中でディスク容量いっぱいになったりとか。 (今はないですかね。) ファイルが壊れてて、あるはずのデータが無かったりとか。
>あとは最初と最後の処理を別ルーチンにしてしまうと可読性が落ちるのか、ありなのか? やってもいいと思いますが、エラー処理ルーチンは、 できるだけすぐに抜けたいので、自分はやらないです。
(でれすけ) 2019/03/15(金) 14:54
お返事ありがとうございます。 >ユニーク関数を追加しない、素直な書き方が受け入れられるのでは…、と思いました。 可読性という意味では、エクセルにない関数はないほうが読みやすいですね。
>DBのトランザクションを掛けたままエラーメッセージ表示した >書き込み途中でディスク容量いっぱいになったりとか。 この二つは共通してI/Oがらみなので、特に気を付けなくてはいけないのは、(読み)書きの場合なので エラートラップ設けるにしろ、特にI/Oに気を付けなければいけない、という感じでしょうか。
>3. 例外発生の有無を条件分岐につかっって、コードを簡略化する については On Error Resume Next Set WB = Workbooks("存在しないブック") On Error Goto 0 If WB Is Nothing Then '〜〜 このような使い方でしょうか?
それで最初に戻ると、私としてはその場でエラー出したいので Sub test4() Application.ScreenUpdating = False Application.DisplayAlerts = False Debug.Print 1 / 0 Application.ScreenUpdating = True Application.DisplayAlerts = True End Sub この形が一番いいと思うようになりました。。。 (稲葉) 2019/03/15(金) 17:36
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.