テキストボックスの半角数字、指定キーのみの入力を許可したい

タグの編集
投稿者 ワシズ  (社会人) 投稿日時 2009/8/20 21:01:33
SP6.0

いつもお世話になっております。

ただいま、テキストボックスの入力制限について考えています。
テキストボックスは以下の条件で制限
・テキストボックスのプロパティIME Modeを3-オフ固定
・テキストボックスには4字までの入力
・「.(小数点)」を入力
・BackSpaceキーも有効

文字数の制限、0~9の半角数字入力、バックスペースの使用、できたのですが、
小数点(vbkeyDecimal)が入力できません。

Private Sub Text1_KeyPress(KeyAscii As Integer)

   '「1-9」[BackSpace]以外の入力はじき、5桁以上は入力不可 
    If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack + vbKeyDecimal Or _
       (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack + vbKeyDecimal) Then
        KeyAscii = 0
    Else
        '全角を半角に変換する 
        KeyAscii = Asc(StrConv(Chr$(KeyAscii), vbNarrow))
    End If

End Sub


上記のコードだと、小数点、バックスペースともに使えません。
+vbKeyDecimalを消すとバックスペースは使えるため、
+vbKeyDecimalの書き方が悪いというのはわかるのですが。
また、vbKeyDecimalは、テンキーの小数点のみ使用ということでしょうか?
vbKeyDecimalを設定した場合、キーの「る」の小数点は使用不可能なのでしょうか?
できれば、キー側の小数点、テンキー側の小数点、どちらも使用可能にしたいですが。。。


ご教示お願いいたします。
投稿者 ?-?  (その他) 投稿日時 2009/8/20 21:31:33
> KeyAscii <> vbKeyBack + vbKeyDecimal
??????
なんで?

KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDecimal
じゃないの?
投稿者 流れ者  (社会人) 投稿日時 2009/8/20 22:16:25
こんにちは。

> KeyAscii <> vbKeyBack + vbKeyDecimal
確かに。「vbKeyBack + vbKeyDecimal」では、vbKeyBackとvbKeyDecimalのコードを足した値との比較になりますね。

>(Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack + vbKeyDecimal)
この場合、既に4桁入力されているので、バックスペースのみ許可すれば良いのでは?
それとも、4桁目に小数点を入れる特殊な操作があるのですか。
投稿者 るしぇ  (社会人) 投稿日時 2009/8/20 22:24:12
修正点については ?-? さんと流れ者さんの指摘でいいと思います。
余談として。。。

コードを選択状態にして[Shift]+[F2]を押すとオブジェクトブラウザで定義が確認できます。
 Const vbKeyBack = 8
 Const vbKeyDecimal = 110 (&H6E)
ということが確認できます。vbから始まるのは定数であり、実際はただの数値データを
キーとして使っているだけだと言うことが分かります。

つまり
> vbKeyBack + vbKeyDecimal
これが意味するのは 8 + 110 = 118(=vbKeyF7)というとんでもないコードになります。

メッセージボックスの引数のように OkCansel ボタン表示かつ情報アイコンといった
場合、それぞれの定数を2の乗数で定義し、ビット表現した場合にそれぞれのビットが
フラグとなるような設計で足し算を使うことはあります。しかしそれにしたって、今回は
ピリオドキーとバックスペースキーの同時押しでは無いのですから、2重に間違ってるな
と気づけます。

ということで、実際にどういう仕組みでプログラムコードが解釈され、実行されるかまで
理解を深め、コードを書く時点で分かるようになることを目標とすればこういった間違い
が理解できるようになります。
投稿者 ワシズ  (社会人) 投稿日時 2009/8/20 23:08:03
?_?さん、るしぇさん

アドバイスありがとうございます。

書き方が思いっきり間違っているようなので、恥ずかしいです。
今後、理解を深め、このような恥ずかしいコーディングはしないように
気をつけます。

流れ者さん
アドバイスありがとうございます。

>>(Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack + vbKeyDecimal)
>この場合、既に4桁入力されているので、バックスペースのみ許可すれば良いのでは?
>それとも、4桁目に小数点を入れる特殊な操作があるのですか。 

4桁目に小数点を入れる特殊な操作はございません。
ただ、テキストボックスを4桁入力に制限したいかったので。
このテキストボックスは、主に5.5、8.4、11.0
といった数字(小数点含)が4桁入力できるテキストボックスです。

アドバイスしていただき、下記のようにコーディングして見ましたが、
半角数字、バックスペースは有効になったのですが、「る」(半角小数点、テンキー「.」が入力されません。
今現在、このテキストボックスには特にプロパティ設定はしておりません。

Private Sub Text1_KeyPress(KeyAscii As Integer)

   '「1-9」[BackSpace]以外の入力はじき、5桁以上は入力不可 
    If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDecimal Or _
       (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDecimal) Then
        KeyAscii = 0
    Else
        '全角を半角に変換する 
        KeyAscii = Asc(StrConv(Chr$(KeyAscii), vbNarrow))
    End If
End Sub


お手数おかけしますが、アドバイスお願いいたします。
投稿者 ?-?  (その他) 投稿日時 2009/8/20 23:37:37
今から馬鹿なことを書く。

> (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDecimal)
4桁「以上」もだめ?
投稿者 ワシズ  (社会人) 投稿日時 2009/8/20 23:51:54
?_?さん

早々のご回答ありがとうございます。
>> (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDecimal)
>4桁「以上」もだめ?

実行してみましたが、だめでした。

また、「1~9」「.」のみを有効にしたコードで試しましたが。

Private Sub Text1_KeyPress(KeyAscii As Integer)

   '「1-9」[.]以外の入力はじき、5桁以上は入力不可  
    If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyDecimal Or _
       (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyDecimal) Then
        KeyAscii = 0
    Else
        '全角を半角に変換する  
        KeyAscii = Asc(StrConv(Chr$(KeyAscii), vbNarrow))
    End If

End Sub


数字は入力できるものの、小数点は入力されませんでした。
根本的に何かの設定に間違い、不足があるのでしょうか?

よろしくお願いいたします。
投稿者 ?-?  (その他) 投稿日時 2009/8/20 23:54:21
だめでした、って何がだめなんですかねー。
具体的にどんなデータを入力したかというのも書いてみてはいかがですか?
5.5とかがだめということ?
110.は、まあ、だめでしょうけど・・・
投稿者 ワシズ  (社会人) 投稿日時 2009/8/21 00:09:14
?-?さん

たびたびのご無礼、大変申し訳ないです。
だめでした。というのは、テキストボックスの中に小数点自体が入力されない、という現象です。

数字を入力すると1111、2222の数字は表示されますが、
.を入力しても小数点が表示されていません。
なので、11.1と入力しようとしても、.が表示されません。

ほかにやり方がありますでしょうか?

ご教示よろしくお願いします。
投稿者 ?-?  (その他) 投稿日時 2009/8/21 00:17:50
KeyAscii <> vbKeyDecimalがだめなのかなぁ?
vbKeyDecimalは定数値としては110という値らしいのでDebugで見てみるとか?
(しかもテンキーの「.」を押したときの値だって?)
もちろん、このときのIf部分は、KeyAscii <> vbKeyDecimalだけにして確認して、だねー。

http://www.red.oit-net.jp/tatsuya/vb/fixed.htm
投稿者 流れ者  (社会人) 投稿日時 2009/8/21 00:22:20
こんにちは。

小数点が入力されない件ですが、おそらく、「Not IsNumeric(Chr$(KeyAscii)) 」で小数点が数値で無いため、はじかれているみたいですね。

あと余談ですが、IF文に限らないことですが、複数の条件をANDとORを混ぜて記述する場合、判断の優先順位が分かるよう、かっこで条件を括るようにした方が、可動性の面と信頼性の面で良いとおもいます。
コードを見た限りでは、コンピュータがどの順番で条件を評価しているか、分かりません。
投稿者 ?-?  (その他) 投稿日時 2009/8/21 00:32:43
> おそらく、「Not IsNumeric(Chr$(KeyAscii)) 」で小数点が数値で無いため

???
> If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack + vbKeyDecimal
True And FalseでElse文実行されません?
勘違い?
Else文に行かなくて困ってるのでは?
投稿者 るしぇ  (社会人) 投稿日時 2009/8/21 00:42:54
?-? さん、流れ者さんの指摘も参考にしつつ、
単純にウチの環境では vbKeyDecimal(110) ではなく vbKeyDelete(46) って出ましたww
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_21733995.html
同様の質問が検索に引っ掛かったので、ボクの環境固有ではないらしい。
サービスパックは5です。
sp5
    Debug.Print Now
    Debug.Print KeyAscii
    Debug.Print Chr(KeyAscii)
    Debug.Print Chr(vbKeyDelete)
    Debug.Print Chr(vbKeyDecimal)
    Debug.Print (Not IsNumeric(Chr$(KeyAscii)))
    Debug.Print (KeyAscii <> vbKeyBack)
    Debug.Print (KeyAscii <> vbKeyDecimal)
    Debug.Print (Not IsNumeric(Chr$(KeyAscii)) _
    And KeyAscii <> vbKeyBack _
    And KeyAscii <> vbKeyDecimal) 

> 2009/08/20 15:24:25 
>  46 
> .
> .
> n
> True
> True
> True
> True
投稿者 流れ者  (社会人) 投稿日時 2009/8/21 00:46:31
こんにちは。

今、改めて、ソースを眺めてみました、

>> If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack + vbKeyDecimal
>True And FalseでElse文実行されません?
おっしゃる通りです。間違えました。すみません。
投稿者 ?-?  (その他) 投稿日時 2009/8/21 00:54:00
興味深いですね。
KeyAscii <> vbKeyDecimalがTrueになってしまうのですか。
テンキー側のほうですよね?(テンキーはDELが割り当てられている。)
テンキーじゃない場合もTrueなのですかね?
投稿者 流れ者  (社会人) 投稿日時 2009/8/21 01:02:16
こんにちは、

ASCIIコード表を見ると、小数点は”46”ですね。

http://www.technoveins.co.jp/technical/data/asciispell.htm

だとしたら、

>If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack + vbKeyDecimal
は、TRUE and TRUE で通りますね。
投稿者 るしぇ  (社会人) 投稿日時 2009/8/21 01:10:22
> テンキー側のほうですよね?(テンキーはDELが割り当てられている。)
> テンキーじゃない場合もTrueなのですかね? 
もち両方テスト済み。同じ結果です。

単独の Delete キーが認識されないのは、このサイトでも紹介されている有名な
話ですが、今回の質問の現象は知らなかったです。
[Visual Basic 中学校 > 初級講座 > 第21回 マウス・キーボードからの入力]
7.KeyPressイベントの詳細
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard21.htm

まぁ、同様の現象なら IsNumeric(Chr$(KeyAscii)) という判定も使っているんだし、
ピリオドのハードコーディングと比較しても良いかなとは思いますが、
なんか、正式なドキュメントが欲しいですよね^^;

>ASCIIコード表を見ると、小数点は”46”ですね。
じゃあ、46でもいいかなぁ・・・歴史的な流れとかなんかはあるかどうかも
知らないので有識者の降臨を待ちますか。
投稿者 ?-?  (その他) 投稿日時 2009/8/21 01:13:49
とすると、
> If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyDecimal 
は、

If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> "."

となるのですかね?

そうすると、

If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack And KeyAscii <>  "." Or _
  (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack And KeyAscii <>  ".") Then

なのですかねぇ?
統一感が無くてちょっと嫌な感じですが・・・

流れ者さん>
コピー元のソース間違えました・・・
投稿者 るしぇ  (社会人) 投稿日時 2009/8/21 01:26:39
> If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> "."
KeyAscii は Integer なので
If Not IsNumeric(Chr$(KeyAscii)) And Chr$(KeyAscii) <> "."
ね。

もしくは
If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> 46
> 統一感が無くてちょっと嫌な感じですが・・・
# vbKeyDelete を使うのは意味ないし^^;
# 全部Chrに統一するのもねぇorz
投稿者 ワシズ  (社会人) 投稿日時 2009/8/21 01:32:49
?-?さん、流れ者さん、るしぇさん

多くの方のたくさんのアドバイス、感謝しております。

るしぇさんのアドバイスに基づき

   '「1-9」[.]以外の入力はじき、5桁以上は入力不可 
    If Not IsNumeric(Chr$(KeyAscii)) And KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDelete Or _
    (Len(Text1.Text) >= 4 And KeyAscii <> vbKeyBack And KeyAscii <> vbKeyDelete) Then
        KeyAscii = 0
    Else
        '全角を半角に変換する 
        KeyAscii = Asc(StrConv(Chr$(KeyAscii), vbNarrow))
    End If
End Sub


で実行したところ、確かに小数点はいりました。
これには正直驚きです。
デバッグでステップ実行をしていくと、小数点が入っているにもかかわらず、
vbKeyDelete「46」が表示されてます。

いま、ASCIIコード表をもとに、16進法の小数点「2E」を関数電卓で10進法に変換したところ、
46という数字が出てきました。
ここからきてるのでしょうかね?
投稿者 流れ者  (社会人) 投稿日時 2009/8/21 01:36:00
こんにちは

VBAですが、検証してました。

Private Sub テキスト1_KeyDown(KeyCode As Integer, Shift As Integer)
    MsgBox ("KeyDown:" + Str(KeyCode))

End Sub

Private Sub テキスト1_KeyPress(KeyAscii As Integer)

    MsgBox ("KeyPress:" + Str(KeyAscii))
End Sub


IMEが英数字入力の状態で

1.テンキーの「.」を押す。
 →"KeyDown:110","KeyPress:46"

2.「る」と書かれたキーを押す
 →"KeyDown:190","KeyPress:46"

どちらも、テキストに入力された文字は小数点「.」

ちなみに、BackSpaceはKeyDown、KeyPress共に8です。

vbKeyDecimalはキーボードのキーに割り当てられた数値を保持しているのでしょうか。 
投稿者 るしぇ  (社会人) 投稿日時 2009/8/21 01:50:43
> いま、ASCIIコード表をもとに、16進法の小数点「2E」を関数電卓で10進法に変換したところ、
> 46という数字が出てきました。
> ここからきてるのでしょうかね? 
引数名が KeyAscii だからねぇ^^;

VB6でも流れ者さんの VBA 検証結果と同じ KeyDown 正常動作確認しました。

あー、なんか見えてきた。引数名が KeyCode と KeyAscii だわ。
えー、もしかしてそういうこと?えー???そんなのあり?
バグじゃなくって仕様と言い切れる引数名だなーorz
投稿者 ?-?  (その他) 投稿日時 2009/8/21 01:55:33
http://park7.wakwak.com/~efc21/cgi-bin/exqalounge.cgi?print+200804/08040058.txt
ここにも似たような話ありますね・・・
投稿者 流れ者  (社会人) 投稿日時 2009/8/21 02:29:04
>あー、なんか見えてきた。引数名が KeyCode と KeyAscii だわ。
>えー、もしかしてそういうこと?えー???そんなのあり?
>バグじゃなくって仕様と言い切れる引数名だなーorz

KeyCode:押したキーの割り当てられた"Key"コード
KeyAscii:押したキーによって入力される"ASCII"コード
ということですか。

変数名が違うわけだから、入ってくる値が違うというのは、
納得せざるを得ない・・・。
投稿者 るきお  (社会人) 投稿日時 2009/8/21 22:24:21
こんにちは。話を戻してしまいますが、
テキストボックスに数字と小数点のみ入力できるようにするコードは次のようになります。

Private Sub Text1_KeyPress(KeyAscii As Integer)

    Dim Letter As String
    Letter = Chr(KeyAscii)
    
    If Not (Letter Like "[0-9.]"Then
        KeyAscii = 0
    End If
    
End Sub


ただし、これだと .... や 1.2.3 など全体としておかしなものも入力できてしまいます。
またコピー&貼り付けを使えばなんでも入れられてしまいます。

ですでの、私は同じことをやりたいとき昔は
KeyPressイベントで頑張って .... や 1.2.3 となる入力を拒否するロジックを実装し、クラスとして共通で使っていました。WithEventsを使用すれば、クラス側に記述したロジックが共通のイベントとして呼ばれるので一度頑張って実装すれば使いまわすことが出来ます。
同じようにしてChangeイベントも実装しコピー&貼り付けも防ぎました。
一度作ってしまえば便利なので何度も利用しましたが、

これから作るのであれば、今後VB6の開発がそう増えるとも思えないので、
仕様を見直して、入力時はなんでも入力できるが[OK]ボタンや、[登録]ボタンなどをクリックしたタイミングで
チェックロジックを実行して、おかしなものが入力されている場合ユーザーに訂正を促すとするのがベターだと思います。(仕様が見直せればの話ですが)