Visual Basic 初級講座 |
Visual Basic 中学校 > 初級講座 >
第19回 コントロールの順序
コントロールの順番は主に[TAB]キーを使ったフォーカスの移動順に関係しますがそれだけではありません。今回はコントロールの順序にかんするトピックをとりあげます。
この回の要約 ・タブオーダー(フォーカスの移動順)はTabIndexとZオーダーで決まる。 ・Zオーダーとはコントロールの重なりの前後関係のこと。 ・SelectNextControlメソッドを使うと、次のコントロールにフォーカスを移動できる。たてえば、[ENTER]キーが押されたら次へ移動するなどの処理ができる。 ・GetNextControlメソッドは次のコントロールを取得できる。工夫次第でいろいろと役に立つ。 |
特に意識していなくても、フォーム上に配置したコントロールには自動的に「順番」が割り当てられます。
「順番」にもいろいろありますが、今回説明する順番は次の3つのことを指しています。
タブオーダー | フォームにコントロールを配置した順番。ただし、ZオーダーやTabIndexの順番を変更することで後からこの順番を変更することができる。 |
Zオーダー | 重なり方の順番 |
TabIndexの順番 | TabIndexプロパティで指定する順番 |
■表1:今回取り上げる「順番」
この表でも簡単に書きましたが、タブオーダーはユーザーが[TAB]キーを押したときにフォーカスが移動する順番です。Zオーダー(読み方:Zオーダー = ゼットオーダー)はコントロールが重なっているときにどのコントロールが手前に来てどのコントロールが後ろになるかという順番です。TabIndex(読み方:TabIndex = タブインデックス)は単純にコントロールのTabIndexプロパティで設定する順番です。
これらを簡単に説明するのならば以上で終わりなのですが、これらの順番をしっかり設定していないために使いにくいプログラムになってしまうこともありますし、逆にこれらの順番をうまく使って効率的にプログラムを組むこともできます。
また、3つの中で特に重要なのはタブオーダーです。タブオーダーはユーザーの操作感や、プログラムの簡潔性にも影響を与えます。 たかだか「順番」と思わないで是非今回の内容を一読してみてください。
今回はZオーダー、TabIndexを説明してから、タブオーダーの活用方法をいくつか紹介します。
Zオーダーはコントロールの重なりの順番のことです。また、重なり方以外にもタブオーダーを決定する要素として使用されます。
■画像1:Zオーダーの違い
上の2つの画像で、左の画像はLabel2の方が前面にあります。右側はLabel1の方が前面にあります。これがZオーダーです。
デザイン時にZオーダーを変更するには、目的のコントロールをクリックしてから[書式]メニューの[順序]を選択するか、レイアウトツールバーのボタンを使います。レイアウトツールバーが表示されていない場合は[表示]メニューの[ツールバー]から[レイアウト]を選択することで表示することができます。
■画像2:Zオーダーを変更するボタン
左のボタンがZオーダーを最前面にするボタンで、右は最背面にするボタンです。
なお、Zオーダーはプロパティではありません。また、どういうわけかZオーダーの操作は「最前面」と「最背面」しかなく、3つコントロールがある場合真ん中の位置にしたいような場合は1つのコントロールを「最前面」にして、また別の1つのコントロールを「最背面」にするという手順を踏むことになります。
私としてはZオーダーもプロパティにして、プロパティウィンドウで指定できると便利だと思うのですが、どうもそのような方法は採用されないようです。なにか理由があるのでしょうか。
さて、プログラムでZオーダーを変更することもできます。コントロールを最前面に移動するにはBringToFrontメソッド(読み方:BringToFront = ブリングトゥーフロント)を使います。最背面に移動するにはSendToBackメソッド(読み方:SendToBack = センドトゥーバック)を使います。
これらのメソッドは引数なしで使用できます。特にサンプルを掲載する必要はないでしょう。
Zオーダーの設定はDockプロパティの効果にも影響を与えます。Dockプロパティは初級講座 第18回 コントロールの配置 で詳しく説明していますが、コントロールを指定した領域に自動的に配置するプロパティです。
■画像3:正常なDock状態
上の画像を見ながらZオーダーとDockプロパティの関係を説明しましょう。上の画像ではPanel1とPanel2とButton1が配置されています。Button2はPanel2の中に配置されています。Panel1のDockはLeft、Panel2のDockはFill, Button1のDockはTopです。
ここで、Panel2のZオーダーを変更して、Panel2を最背面に移動するとレイアウトは次のように変わります。
■画像4:誤ったDock状態
Panel2がPanel1の背面にもぐりこんだ結果です。
TabIndexはすぐ後で説明するタブオーダーを決定する要素の1つです。複数のコントロールに同じTabIndexを割り当てることもできます。
ユーザーが[TAB]キーを押したとき、フォーカスはTabIndexが小さい方からTabIndexが大きい方へ移動します。
通常はフォームに貼り付けた順に連番でTabIndexが自動的に割り当てられますので、フォームにコントロールを貼り付ける時点でフォーカスの移動のことを考慮しておくと、後でTabIndexを割り当てなおす必要がなくなるので楽です。
タブオーダーは文字通り[TAB]キーが押されたときにフォーカスが移動する順番です。Windowsでは[TAB]キーを使ってフォーカスを順番に移動できると言う決まりがあります。
ちゃんとしたアプリケーションはタブオーダーがフォームの左上から右下に向かって綺麗に設定されています。ためしに、Windowsの何かの設定画面を表示して[TAB]キーを何度も押してみると分かります。
タブオーダーはプロパティではありません。タブオーダーはTabIndexプロパティの順番で決定し、TabIndexが同じコントロールがある場合にはZオーダーの順番で決定されます。Zオーダーは前面にあるものが優先されます。
また、後になってからタブオーダーを変更する場合は、プロパティウィンドウのTabIndexプロパティを手動で変更しなくても、便利な編集画面を使用することができます。[表示]メニューの[タブオーダー]を選択するとこの画面を表示することができます。
■画像5:タブオーダー設定画面
この画面ではコントロールの左側に現在のタブオーダーを現す数値が表示されていて、コントロールを順番にクリックすることでタブオーダーの順番を変更することもできます。
なお、TabStopプロパティ(読み方:TabStop = タブストップ)がFalseの場合にはそのコントロールに[TAB]キーでフォーカスを移動することはできません。また、Labelなど本来フォーカスを取得できないコントロールにもタブオーダーはありますが、実際にフォーカスを移動することはできません。[TAB]キーが押された場合、こういったコントロールは無視されてさらにその次のコントロールにフォーカスが移動します。
このフォーカスの移動順序の設定によってユーザーの操作感が大きく変わる場合もあるので、アプリケーションを公開・配布する場合にはできるだけユーザーが使いやすい順番でTabIndexを設定するように心がけましょう。
さて、このタブオーダーはフォーカスの移動順だけではなく、SelectNextControlメソッド(読み方:SelectNextControl = セレクトネクストコントロール)と、GetNextControlメソッド(読み方:GetNextControl = ゲットネクストコントロール)に影響を与えます。
SelectNextControlメソッドはフォーカスを次のコントロールに移動するメソッドです。たとえば、次のように使います。
Me.SelectNextControl(Button1, True, True, True, True) |
■リスト1:フォーカスを次のコントロールへ移動する
このコードを実行すると、フォーカスはButton1の次のタブオーダーのコントロールに移動します。しかし、この例はそれほど役に立ちません。特定のコントロールに移動するのであればFocusメソッドを使った方が簡潔だからです。この例が役に立つとしたらButton1の次のコントロールが場合によって違う時でしょうか。
それはどんな場合かと思われるかもしれないので少し補足しておきます。Button1, Button2, Button3と並んできるとき通常はButton1の次のコントロールはButton2ですが、たとえば、Button2のEnabledプロパティがFalseの場合は、Button2は使用不可ですから次のコントロールはButton3となります。SelectNextControlメソッドを使えばこういった判定を自動的に行ってくれます。
さて、SelectNextControlメソッドは第一引数にActiveControlプロパティを指定 して便利に使うこともできます。
ActiveControlプロパティとはフォームなどのコンテナが持っているプロパティで、現在フォーカスのあるコントロールを表しています。そのため、次のコードは[ENTER]キーが押されると自動的に次のコントロールにフォーカスが移動します。
Private Sub Form1_Load(ByVal
sender As
System.Object, ByVal
e As
System.EventArgs) Handles MyBase.Load Me.KeyPreview = True End Sub |
Private
Sub
Form1_KeyPress(ByVal
sender As
Object,
ByVal e
As
System.Windows.Forms.KeyPressEventArgs)
Handles
MyBase.KeyPress
If e.KeyChar = Chr(Keys.Enter) Then Me.SelectNextControl(Me.ActiveControl,
True,
True,
True,
True) End If End Sub |
■リスト2:[ENTER]キーが押されたときにフォーカスを次のコントロールへ移動する
最初にKeyPreviewプロパティ(読み方:KeyPreview = キープレビュー)をTrueしていますが、フォームのイベントでキーボードの入力をキャッチするためにこの処置が必要です。 また、途中に出てくるe.Handled = True (読み方:Handled = ハンドルド)はそのキーに関する処理が終了したことを.NET Frameworkに通知します。この処理は必須ではありませんが、はずすといちいちピーピー音が鳴ってうるさいです。
ただし、ActiveControlの種類によってはフォーカスが移動できない場合があります。たとえば、ActiveControlがボタンの場合はいくら[ENTER]キーを押してもフォーカスは移動しません。これは、ボタンにフォーカスがあるときに[ENTER]キーを押すとボタンのクリックイベントが発生するからです。
SelectNextControlメソッドは第2引数以降を使ってもっと違う動きをさせることもできます。第2引数をFalseにすると、次のコントロールへ移動するのではなく、前のコントロールに移動します。第3引数をFalseにすると、TabStopがFalseのコントロールにもフォーカスが移動できます。
GetNextControlメソッドは特にアクションを起こすわけではなく、次のコントロールを取得するだけです。これはActiveControlが現在フォーカスのあるコントロールを表しているのに似ています。
「次のコントロール」を取得することの利点はなんでしょうか?
よくあるのは、業務アプリケーションなどで「コード」を入力させるシーンです。たとえば、店コードを入力するテキストボックスがあったとしましょう。そして、その後ろにはそのコードに対応した店名を表示するラベルがあったとします。
■画像6:業務アプリケーションでよくあるコードと名前の組み合わせ
この場合、次のように書くと店名をスマートに表示させることができます。
Private
Sub txtStoreCode_Validated(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles
txtStoreCode.Validated Dim StoreName As String = GetStoreName(txtStoreCode.Text) GetNextControl(txtStoreCode, True).Text = StoreName End Sub |
Private Function
GetStoreName(ByVal StoreCode
As String)
As
String '本来はここにデータベース等から店名を取得する処理を書く Return "Visual Basic 中学校" End Function |
■リスト3:コードが入力されたときに名前を表示する。
しかし、このくらいならまだそれほど利点が感じられません。GetNextControlの代わりのラベル名を書いてもそれほど違いはないからです。ラベル名に関係なく次のコントロールに店名を表示できると言うのが唯一のメリットです。
Validatedイベント(読み方:Validated = バリデイテッド)について少し補足しておきます。このイベントは入力チェックの後、フォーカスが移動する直前に発生します。詳しく言うとコントロールがフォーカスを失う直前に発生するイベントで、フォーカスの移動をキャンセルできるValidatingイベント(読み方:Validating = バリデイティング)の直後に発生します。
さて、今度は、同じコードを表すテキストボックスとそれに対応する名前を表示するラベルが何行か並んでいるシーンを考えて見ます。たとえば、下の画像のように店員コードと店員名を複数表示できる画面を考えて見ましょう。
■画像7
このとき、店員コードを入力すると店員名が表示されるのですが、すべてのテキストボックスに店員名を表示するプログラムを書かなければいけないと感じていませんか? もちろんそんなことはありません。GetNextControlを使えば、すべての処理を一箇所にまとめることができます。次のようになります。
Private
Sub txtPersonCode_Validated(ByVal
sender As Object,
ByVal e As
System.EventArgs) _ Handles txtPersonCode1.Validated, txtPersonCode2.Validated, txtPersonCode3.Validated Dim StoreName As String = GetPersonName(sender.Text) GetNextControl(sender, True).Text = StoreName End Sub |
Private Function
GetPersonName(ByVal PersonCode
As String)
As
String
'本来はここにデータベース等から店員名を取得する処理を書く Return "店員 第" & PersonCode & "号" End Function |
■リスト4
これなら十分に利点を感じられます。3つのテキストボックスそれぞれについてIf文などを使って処理を分岐させる必要はまったくありません。VBではこのように同じようなコードを何度も書かなくてすむような仕組みがいろいろと用意されています。
今回はGetNextControlの説明でこの例をあげましたが、この例には、他にもHandles句を使った複数のイベントの処理や、senderを使ったイベント発生源の取得などを利用しています。イベントについてのこれらの仕組みについては初級講座 第10回 イベントプロシージャで説明しています。