連載:VB 6ユーザーのための
これならマスターできるVB 2005超入門

第4回 トラブルは水際で防げ〜入力時のチェックとエラー処理

羽山 博
2006/11/22
Page1 Page2 Page3 Page4

■Validatingイベントを使って入力チェック

 商品コードを入力し終わったときには、入力されたデータが8桁であるかどうかを調べるので、txtCodeコントロールのValidateイベント・ハンドラを書けばよい。

 これには、txtCodeコントロールをクリックして、プロパティ・ウィンドウの[イベント]ボタンをクリックする。そして図3のように、Validatingイベントの欄にイベント・ハンドラの名前を入力しよう(ここではlengthCheckとした)。


図3 Validatingイベント・ハンドラを作成する
Validatingイベントの欄にイベント・ハンドラの名前を入力する。
  txtCodeコントロールをクリックする。
  [イベント]ボタンをクリックする。
  イベント・ハンドラの名前として「lengthCheck」と入力する。

 lengthCheckイベント・ハンドラの内容は以下のとおり。プログラムの実行時にtxtCodeコントロールにデータを入力した後、[Tab]キーを押すなどしてほかのコントロールにフォーカスを移すと、このコードが実行される。

 txtCodeコントロールのTextLengthプロパティが8でない場合には、引数として渡されている「e」というオブジェクトのCancelプロパティをTrueにする。このeというのは、キャンセルできるイベントのデータを表すCancelEventArgクラスのオブジェクトなのだが、そのあたりは分からなくても差し支えない。CancelプロパティにTrueを設定すると、Validatingイベント以降のイベントが発生しなくなり、フォーカスの移動がキャンセルされる。つまり8桁の商品コードを入力するまでフォーカスを移動できないというわけだ

 続いて、エラー・メッセージを表示し、txtCodeコントロールのSelectメソッドを使ってテキストボックス中の文字列を選択された状態にすれば、入力チェックの出来上がりとなる。

' 商品コード・テキストボックスのValidatingイベント・ハンドラ
Private Sub lengthCheck(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles txtCode.Validating
  If txtCode.TextLength <> 8 Then
    e.Cancel = True
    lblAlert.Text = "商品コードは8桁です"
    txtCode.Select(0, txtCode.TextLength)
  Else
    lblAlert.Text = ""
  End If
End Sub
商品コードが8桁でない場合、再入力させるValidatingイベント・ハンドラ

 あとは、[キャンセル]ボタンと[OK]ボタンのイベント・ハンドラを書いておけばよい。ここでは実際にデータベースの検索や更新は実行しないので、取りあえずは、いずれの場合もプログラムを終了させるだけとする。[OK]ボタンの方は、今後のことも考えて、イベント・プロシージャの名前をupdateDBとしてある。

' [キャンセル]ボタンのイベント・ハンドラ
Private Sub exitProc(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
  Application.Exit()
End Sub

' [OK]ボタンのイベント・ハンドラ
Private Sub updateDB(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
  Application.Exit()
End Sub
[キャンセル]ボタンと[OK]ボタンのイベント・ハンドラ

 実行結果は最初に示した図1のような感じになる。

■プログラムが終了できない!

 さて、入力チェックが簡単になって、メデタシ、メデタシといいたいところだが、そうは問屋が卸さない。なんと、このプログラムには、正しい商品コードを入力しない限り終了できないという問題がある! [キャンセル]ボタンをクリックしても、プログラムは終了できないのだ。なぜなら、Validatingイベントを利用して入力チェックをしたせいで、入力が正しくないとフォーカスが移動しなくなったからだ。

 そんなときにはどうするか?

 誰もが、txtCodeコントロールのプロパティやメソッドの中に、対処法があると思うだろう。まず、Validatingイベント・ハンドラで何とかできるのでは、と考えるのが普通だと思う(確かにそれでもできる)。だが、それよりもはるかに簡単な方法がある。btnCancelコントロールのCausesValidationプロパティをFalseに設定しておくだけでよい。

 つまり、

「フォーカスが移る先のコントロールでCausesValidationプロパティがFalseになっていれば、元のコントロールのValidatingイベントは発生しない」

ということだ。よーく意味をかみしめてほしい。次のコントロールのプロパティが、前のコントロールのイベントに影響するというのは不自然な感じがして違和感を覚えるかもしれないが、実際に使ってみると理にかなっているということが分かる。

 Causeというのは「原因となる」とか「引き起こす」という意味。だから、CausesValidationというのは「このコントロールは(フォーカスを移そうとしたときに、前のコントロールの)Validationを引き起こす」という意味だ。

 重要なので、図でもう一度確認しておいてほしい(図4)。


図4 CausesValidationプロパティの働き
CausesValidationプロパティをFalseに設定しておくと、フォーカスが移ってきた元のコントロールでValidatingイベントが発生しなくなる。

 当然のことだが、CausesValidationプロパティがTrueになっていると、フォーカスが移動しないということではない。あくまでも、前のコントロールでValidatingイベントが発生しないというだけのことである。フォーカスが移動しないようにするには、Validatingイベント・ハンドラの中でCancelEventArgsオブジェクトの(eという名前の引数の)CancelプロパティをTrueに設定する必要がある。

■一難去ってまた一難

 [キャンセル]ボタンや[ヘルプ]ボタンのように、入力チェックとは関係なく選択できるようにしたいコントロールでは、CausesValidationプロパティをFalseにしておけばいいということが、先ほどの例で分かったと思う。

 ところがこのプログラムは、まだ思ったとおりに動いてくれない。[キャンセル]ボタンをクリックして、プログラムを終了させることはできるのだが、フォーム右上の[×]ボタンをクリックしたときや、[Esc]キーを押してキャンセルしようとしたときにはValidatingイベントが発生してしまう。フォームのCausesValidationプロパティをFalseにすればうまくいきそうだが、そうすると、フォームの何もコントロールのない部分をクリックすると、フォーカスが移動してしまう。

 ここで八方ふさがり、まさにお手上げ状態になってしまいそうなのだが、抜け道が1つだけある。またもや違和感を覚えるかもしれないが、Validatingイベントが発生したときには、フォームのアクティブなコントロールを示すActiveControlプロパティはすでに次のコントロールになっているのである(図5)。


図5 Validatingイベント発生時のActiveControlプロパティの変化
txtCodeコントロールからtxtQuantityコントロールへと[Tab]キーやマウスのクリックでフォーカスを移動させると、txtCodeコントロールでValidatingイベントが発生し、そのイベント・ハンドラが実行されるが、その時点ではActiveControlプロパティはtxtQuantityコントロールを指している。

 ところが、[Esc]キーを押した場合やフォームの[×]ボタンをクリックした場合は、ActiveControlプロパティが前のコントロールのままになっている。つまり、txtCodeコントロールがまだActiveControlプロパティにセットされたままなのだ(図6)。


図6 フォームの[×]ボタン・クリック時にはActiveControlは変わらない
フォームの[×]ボタンをクリックした場合や[Esc]キーを押した場合は、txtCodeコントロールのValidatingイベントは発生するが、ActiveControlプロパティはtxtCodeコントロールのままとなっている。

 ということは、ActiveControlプロパティがtxtCodeであれば、イベントのキャンセルやエラー・メッセージの表示をしないようにすればよい。逆にいうと、ActiveControlプロパティがtxtCodeでない場合だけ、イベントのキャンセルとエラー・メッセージの表示をすればよい。

 では、コードを書いてみよう。txtCodeコントロールのValidatingイベント・ハンドラを以下のように書き換える。

' 商品コード・テキストボックスのValidatingイベント・ハンドラ
Private Sub lengthCheck(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles txtCode.Validating
  If txtCode.TextLength <> 8 And ActiveControl IsNot txtCode Then
    e.Cancel = True
    lblAlert.Text = "商品コードは8桁です"
    txtCode.Select(0, txtCode.TextLength)
  Else
    lblAlert.Text = ""
  End If
End Sub
フォームの[×]ボタンをクリックしたときや[Esc]キーを押したときにプログラムが終了できるようにするコード

 細かい話だが、IsNot演算子はVB 2005で利用できる新しい演算子である。VB 6では、

Not ActiveControl Is txtCode

のように書いていたはずだ。ちょっとしたことだが、コードがずいぶん見やすくなる。


 INDEX
  連載:VB 6ユーザーのためのこれならマスターできるVB 2005超入門
  第4回 トラブルは水際で防げ〜入力時のチェックとエラー処理
    1.サンプル・プログラム4 − データベース検索のためのダイアログ
  2.Validatingイベントを使って入力チェック
    3.構造化例外処理を使おう
    4.統一感のある構造化例外処理とFinallyの落とし穴
 
インデックス・ページヘ  「これならマスターできるVB 2005超入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH