長谷川 裕行 (はせがわ ひろゆき)
有限会社 手國堂 代表取締役
http://www.hirop.com/
テクニカルライターとして活躍。プログラミングに関する著書多数、DB Magazineなどにも多くの記事を提供している。 |
コンピュータは、元々キーボードで操作するものでした(もっと昔には、ケーブルやスイッチ、パンチカードなどを使っていましたが、まあ、そこまで昔の話はやめておきましょう)。ところが、今や入力機器の主役はマウスとなり、キーボードは文字や数字を入力するだけの装置となった感があります。
が、実際には、まだまだキーボードだけでコンピュータを操作している人はいます。GUIが当たり前だからといって、すべてのユーザーにマウス操作を強要することはできません。
今回は、キーボード中心の操作と、マウスなしで扱えるアプリケーションのインターフェイスについて考えてみます。
「Windowsだからマウスで操作して当り前」という発想は、業務アプリケーションには通用しません。マウスを使わなくても操作できるよう、工夫する必要があります。
- キーボードで操作したいユーザー -
Windowsアプリケーションは通常マウスで操作し、キーボードを扱うのは数値や文字を入力するときくらいです。そのためアプリケーションの開発時に、キーボード関係のユーザーインターフェイスをおろそかにしてしまいがちです。
しかし、ユーザーの中にはマウスが苦手な人もいます。特に業務用アプリケーションでは、マウスを装備していないオフコンや汎用機の端末操作に慣れている人がたくさんいます。そういう人たちは、「Windowsマシンでもできるだけキーボードで操作したい」と願っています。
そんな要望を聞いて、「Windowsはマウスを使うものだから、マウスの練習をしてください」などと冷たいことは言えません。
- Windowsのキー操作 -
基本的にWindowsは、すべてをキーボードで操作することも可能です。以下の表に、業務用アプリケーションでよく行う操作と、それを実行するためのキー操作の対応を掲げておきます。
表1:アプリケーションの操作とキー操作の対応
機能 |
キーの操作 |
コマンドボタンのクリック |
[Enter]キー |
リストのスクロールと選択 |
カーソルキー([↑][↓])と[Enter]キー |
オプションボタンの選択 |
カーソルキー([↑][↓]) |
チェックボックスのON/OFF |
スペースキー |
ドロップダウンリストの表示 |
[F4]キーまたはカーソルキー([↓]) |
コントロール間のフォーカス移動 |
[Tab]キー |
- フォーカス移動と[Tab]キー -
コマンドボタンのクリックやチェックボックスのON/OFFなど、個々のコントロールの操作はWindowsが司っているため、アプリケーション開発時に特に気にかける必要はありません。操作マニュアルなどに、そのことを明記しておけばよいでしょう。
問題はコントロール間のフォーカス移動です。上記の基本的なコントロールの操作は、すべてそのコントロールがフォーカスを受け取っているときに有効です。あるコントロールから異なるコントロールへとフォーカスを移動するには、表にあるように[Tab]キーを使います。この操作自体はWindowsが制御していますが、フォーカスが移動する順序は開発者が設定しなければなりません。このフォーカス移動順を「タブオーダー」(tab
order)と言います。
[Tab]キーによるフォーカス移動の設定を忘れると、とんでもないユーザーインターフェイスになってしまいます。サンプルで確認してみましょう。
- 販売管理の入力画面 -
サンプルアプリケーション(ex20.exe)を起動し、[サンプル1]ボタンをクリックすると、画面1のようなウィンドウがオープンします。販売状況を入力する画面です。但し、これはフォーカス移動のためのサンプルなので、実際のデータ登録はできません。
画面1:販売状況の入力画面(サンプル1)
このアプリケーションでは、背景色が白のテキストボックス「日付」「顧客番号」「商品番号」「数量」にデータを入力すれば、背景色が灰色のテキストボックス「顧客名」「商品名」などに該当データが表示されるようになっています。
- フォーカス移動が乱れる! -
問題は、テキストボックスの移動順です。マウスでテキストボックスをクリックするなら問題はありませんが、キーボードからの操作では入力を終えたら[Tab]キーで次の入力欄に移動することになります。実際に試してみてください。フォーカスが予測していないテキストボックスやコマンドボタンに移動し、混乱するはずです。
- フォーカス移動に注意する -
VBのフォームデザインでは、コントロールのタブオーダーはフォームに貼り付けた順に設定されます。そのため、開発時の操作手順によってはとんでもない移動順となる場合があります。
このサンプルのように文字列データの入力を連続して求める仕様なら、動作チェックによって問題点はすぐに発見できます。が、チェックボックスやオプションボタン、リストボックスを多用したフォームでは、マウスでフォーカスを動かすことが多いため、キーボードによるフォーカス移動が意識の外に追いやられる場合もあり得ます。
- TabIndexプロパティを設定する -
明示的にタブオーダーを設定するには、各コントロールのTabIndexプロパティを設定します。TabIndexは0から始まる整数で、[Tab]キーを押すと数値の小さい方から大きい方へ向かって、フォーカスが順次移動するようになります。
但し、EnabledプロパティをFalseに設定したコントロール(例では、背景色が灰色のテキストボックス)ではTabIndexは意味をなさず、何番に設定されていてもフォーカスを受け取りません。
次に、フォーカス移動順を適切に設定したサンプルを試してみましょう。キーボードだけで操作すれば、その違いが分かるはずです。
- フォーカスが循環する仕様 -
サンプルアプリケーションのメニューから[サンプル2]ボタンをクリックすると、先ほどと同じフォームが表示されます。こちらは、タブオーダーを適正に設定してあります。
まず「日付」がフォーカスを受け取り、次いで「顧客番号」→「商品番号」→「数量」…とテキストボックスのフォーカスが移動し、その後コマンドボタン[更新]→[閉じる]の順に移動します。
[閉じる]ボタンがフォーカスを受け取っているときに[Tab」キーを押すと、「日付」テキストボックスにフォーカスが移動します。つまり[Tab]キーを押すごとに、上から下へと順次フォーカスが切り替わり、ぐるぐると回るようになっているのです。1つ前のコントロールに戻すには[Shift]+[Tab]キーを押します。
なお、ADOデータコントロールにはTabIndexプロパティがないため、フォーカスの移動はマウスのクリックで行います。
- データベースアプリは特に注意 -
すべてをマウスで操作できるユーザーなら、サンプル1とサンプル2は同じ操作感となるでしょう。しかし、キーボードしか使わないユーザーが操作する場合、どちらが扱いやすいかは明白です。
特に、データベースを元にした入力用フォームの場合は、デザイン時にテキストボックスを貼り付ける順番を考慮しておきましょう。うまく貼り付けていけば、あとからTabIndexを設定し直す必要はなくなります。
そういう意味では、データフォームウィザードを使ってフォームを作るのもよいでしょう。但し、設計・開発者が期待する入力順と、元になったレコードソースのフィールドの構成順が一致していなければなりません。
- ウィザードの問題点 -
データフォームウィザードを使う場合、もう1つ問題があります。データフォームウィザードでは、基本的に、Boolean型(AccessでいうYes/No型)のフィールド以外は、すべてテキストボックスになってしまいます。
フィールドの内容によっては、あとからオプションボタンを追加したり、リストボックス、コンボボックスなどに置き換えたりする必要が生じます。その場合、後から貼り付けたコントロールのタブオーダーは当然後ろに回されます。
結局、コントロールのTabIndexを設定し直さなければなりません。但し、TabIndexプロパティは自動調整されるため、すべてを見直す必要はありません。
例えば、TabIndexが3と4の2つのテキストボックスがあり、3のテキストボックスの次に追加したコンボボックスにフォーカスを移動させたい場合、コンボボックスのTabIndexを4に設定すれば、それまで4だったテキストボックスのTabIndexが自動的に5に変更されます。
フォーカス移動のためのキーが[Tab]キーだけでは、ちょっと扱いにくいと感じる人もいるはずです。さらに扱いやすい仕様を考えてみましょう。
- カーソルキーで移動させる -
すべての項目を入力しなければならない場合ならともかく、たくさんの項目の中の一部だけを書き換えたいような場合、[Tab]キーだけではなく、カーソルキー[↑][↓]でもフォーカスを移動できる方が便利でしょう。
但しテキストボックスの場合、[←][→]キーはボックス内のカーソル移動の役目があるため、この仕様が役に立つのは入力の必要なテキストボックスが上下に並んでいる場合に限られます。 |
|
- 押されたキーを取得するイベント -
上記の仕様を満たすには、押されたキーを判別しその種類によって次の移動先を切り替える必要があります。
各オブジェクトは、キーボードのキーが押されるとKeyDownおよびKeyPressイベントが発生します。それぞれのイベントに対応するプロシージャの定義を見ておきましょう。
KeyPressイベント
・ |
プロシージャ定義 |
|
Private Sub オブジェクト名_KeyPress _
(keyascii As Integer)
または
Private Sub オブジェクト名_KeyPress _
(Index As Integer, keyascii As Integer) |
・ |
引数 |
|
Index:コントロール配列のインデックス
keyascii:押されたキーのASCIIコード |
引数を見れば分かるように、KeyPressイベントは押されたキーの文字コードを取得する場合に用いられます。そのため、[Ctrl]キーやファンクションキーの押し下げ状態は取得できません。
KeyDownイベント
・ |
プロシージャ定義 |
|
Private Sub オブジェクト名_KeyDown _ (keycode
As Integer, shift As Integer) または Private Sub オブジェクト名_KeyDown
_ (Index As Integer, keycode As Integer, shift As Integer) |
・ |
引数 |
|
Index:コントロール配列のインデックス
keycode:押されたキーのキーコード
shift:[Shift][Ctrl][Alt]の各キーの押し下げ状態 |
引数shiftの値は、以下の表に示す記号定数で判別できます。この値はビットマスクなので、値の和で複数のキーを示せます。例えば、[Shift]+[Ctrl]が押されていれば、shiftの値は
vbShiftMask + VbCtrlMask
となります。
表1:[Shift][Ctrl][Alt]の各キーを示す記号定数
記号定数 |
値 |
キー |
vbShiftMask |
1 |
[Shift]キー |
VbCtrlMask |
2 |
[Ctrl]キー |
VbAltMask |
4 |
[Alt]キー |
引数keycodeも記号定数化されているため、プロシージャ内で容易に押されたキーを判別できます。但しshiftのようなビットマスクではないので、値の和で複数キーの押し下げを判別することはできません。以下の表を参照してください。
表2:押されたキーを示すキーコード(主なもの)
分類 |
記号定数 |
値 |
キー |
制御キー |
|
|
|
vbKeyBack |
8 |
BackSpace |
|
vbKeyTab |
9 |
Tab |
|
vbKeyClear |
12 |
Clear |
|
vbKeyReturn |
13 |
Enter |
|
vbKeyShift |
16 |
Shift |
|
vbKeyControl |
17 |
Ctrl |
|
vbKeyEscape |
27 |
Esc |
|
vbKeySpace |
32 |
スペース |
|
vbKeyPageUp |
33 |
PageUp |
|
vbKeyPageDown |
34 |
PageDown |
|
vbKeyEnd |
35 |
End |
|
vbKeyHome |
36 |
Home |
|
vbKeyLeft |
37 |
← |
|
vbKeyUp |
38 |
↑ |
|
vbKeyRight |
39 |
→ |
|
vbKeyDown |
40 |
↓ |
|
vbKeyPrint |
42 |
PrintScreen |
|
vbKeyInsert |
45 |
Insert |
|
vbKeyDelete |
46 |
Delete |
|
vbKeyNumlock |
144 |
NumLock |
文字キー |
|
|
|
vbKeyA |
&H41(65) |
A |
|
vbKeyB |
&H42(66) |
B |
|
vbKeyC |
&H43(67) |
C |
|
(途中省略) |
|
|
|
vbKeyX |
&H58(88) |
X |
|
vbKeyY |
&H59(89) |
Y |
|
vbKeyX |
&H5A(90) |
Z |
|
vbKey0 |
&H30(48) |
0 |
|
vbKey1 |
&H31(49) |
1 |
|
vbKey2 |
&H32(50) |
2 |
|
(途中省略) |
|
|
|
vbKey8 |
&H38(56) |
8 |
|
vbKey9 |
&H39(57) |
9 |
テンキー |
|
|
|
vbKeyNumpad0 |
96 |
0 |
|
vbKeyNumpad1 |
97 |
1 |
|
vbKeyNumpad2 |
98 |
2 |
|
(途中省略) |
|
|
|
vbKeyNumpad8 |
104 |
8 |
|
vbKeyNumpad9 |
105 |
9 |
|
vbKeyMultiply |
106 |
*(乗算記号) |
|
vbKeyAdd |
107 |
+(加算記号) |
|
vbKeySeparator |
108 |
Enter |
|
vbKeySubtract |
109 |
-(減算記号) |
|
vbKeyDecimal |
110 |
.(小数点) |
|
vbKeyDivide |
111 |
/(除算記号) |
ファンクションキー |
|
|
|
vbKeyF1 |
112 |
F1 |
|
vbKeyF2 |
113 |
F2 |
|
vbKeyF3 |
114 |
F3 |
|
(途中省略) |
|
|
|
vbKeyF10 |
122 |
F14 |
|
vbKeyF11 |
123 |
F15 |
|
vbKeyF12 |
124 |
F16 |
- KeyDownイベントを処理する -
ここでは、カーソルキーの押し下げ状態を識別する必要があります。従って、「日付」「顧客番号」などのテキストボックスのKeyDownイベントで、[↑]キーが押されたら1つ前[↓]キーが押されたら次のコントロールにフォーカスを移動する処理を設定すればよいことになります。
- コマンドボタンの設定 -
コマンドボタンは、元々[↑][↓]キーの入力で前後のコントロールにフォーカスを移動するようになっているため、KeyDownイベントを処理する必要はありません。ただ、TabIndexを以下のように設定しておきます。
[閉じる]:10
[更新]:9
こうすることで、
[閉じる]にフォーカスがあるとき
[↑]を押せばフォーカスが[更新]に移動
[↓]を押せばフォーカスが「日付」に移動
[更新]にフォーカスがあるとき
[↑]を押せばフォーカスが「数量」に移動
[↓]を押せばフォーカスが[閉じる]に移動
という動作になります。
TabIndexが最大のコントロールで次にフォーカスを移動すると、フォーカスは最小のTabIndexを持つコントロールに移ります。このことを利用して、一番上にあるコマンドボタンを最大値、一番下にあるコマンドボタンをその1つ前の値に設定しておくのです。
- 押されたキーによってフォーカスを移動する -
あとは、テキストボックスのKeyDownイベントプロシージャを、リスト1のように設定します。単に「押されたキーを判断し、フォーカスの移動先を切り替えている」だけです。
テキストボックスはコントロール配列となっているため、
Case 38: ' ↑
cmdClose.SetFocus
Case 40: ' ↓
txtDatField(2).SetFocus
といったスタイルのコードが並び、冗長になっています。実際には、コントロール配列の要素番号(Indexプロパティ)の設定を工夫することで、もっとシンプルなコードにできます。
但し、そうするとレコードソースのフィールド構成との整合を取るのが難しくなります。このあたりが工夫のしどころなのですが、今回のサンプルではキーコードの取得とその処理の様子を見ていただくために、敢えて工夫を施さないままとしておきました。
データベースとの接続やフィールド設定などの処理については、今回のテーマとは関係がないためリストは掲載していません。サンプルのプロジェクトを開いて、確認してください。
リスト1:テキストボックスでのキーボード操作を処理する
注意
サンプルでは、mdbファイル「販売.mdb」をオープンして表示するようになっています。サンプルを試す場合、「販売.mdb」もプロジェクトと同じフォルダに保存してください。ex20.exeを実行する場合も同じです。データベースに関するエラー処理は施してありませんので、ご注意ください。
VBプロジェクトファイルのダウンロード
(LZH形式 55.8KB) |