入力チェック への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/5/24 01:46:15
> TryParseは数値変換して変換が成功したか失敗したかを返すのはわかるんですけれども。。。 

そうですね。TryParse が False を返した場合、それは
非数値が入力されていた(または空欄だった)ことを意味します。

そして TryParse は、数値変換が成功した場合、True を返すだけではなく
出力引数に渡された変数 d に対して、変換結果の値をセットする仕様です。
(ちなみに変換に失敗した場合には、d にゼロがセットされます)


そして当初の仕様では、変換結果は正数でなければならず、ゼロや負数に対しては、
> MsgBox("0か負の値がはいっています")
を表示して、入力欄を赤く染め上げることが目的だったわけですから、
単に数値変換できただけでは不十分であり、そこからさらなる追加判定で、
変換結果の d の値が 0 よりも大きければ正常、
0 以下ならが赤くするという追加判定も必要になりますよね。

そのための「AndAlso」です。
投稿者 kkkkk   (社会人) 投稿日時 2018/5/23 20:20:01
教えていただきありがとうございます。もう1つ教えていただきたいです。

>If Decimal.TryParse(sender.Text, d) AndAlso d > 0.0d Then

ここの部分のAndAlso d の意味がなぜ必要なのかわからないです

TryParseは数値変換して変換が成功したか失敗したかを返すのはわかるんですけれども。。。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/5/22 00:31:46
> For Each ctl As Control In Me.Controls
>  If TypeOf ctl Is TextBox  Then

この Form_Load 側のコードについては、
TypeOf 演算子の代わりに
OfType 拡張メソッドを使うと、スッキリ書けますよ。


> AddHandler CType(ctl, TextBox).Click, AddressOf TextBox_textbox_leave

最初の質問では Leave イベントを使っていましたよね。
今回は何故 Click イベントなのでしょうか?


> If Val(CType(sender,TextBox).Text) <= 0 Then 

Val は、常に数値変換に成功するとは限りませんので、
このようなケースで Val() を使うことはおすすめしません。

たとえば Val("1.2%") や Val("-5.2&") なら InvalidCastException を発しますし、
Val("32768%") や Val("1.8d308") なら OverflowException を発することになります。

代わりに、Integer.TryParse や Decimal.TryParse の利用を
検討してみてください。これなら例外になってしまうこともありません。


> MsgBox("0か負の値がはいっています")
> TextBox1.BackColor = Color.Red

上記だと、常に TextBox1 の色が変化してしまいます。
イベントハンドラの引数 sender には、そのイベントの対象となるコントロールが
セットされていますので、最初に rvf さんが書かれた通り、sender を活用しましょう。

それと上記の順だと、メッセージを閉じるまで色が変わらないので、
色を変えてからメッセージを出した方が良いかも知れません。
(画面構成によっては、メッセージの後で色を変えた方が良い場合もあるので、
 一概にどちらが良いとは言い切れませんが)


> TextBox1.BackColor = Color.White

色を戻すときには、Color.White をセットするのではなく、
Color.Empty をセットするか、または ResetBackColor メソッドを
呼び出すことをお勧めします。

背景色を変更していない TextBox を Enabled = False にした場合と
背景色を変更してから Enabled = False にした場合とを比べてみると
表示が異なってくることになります。
https://www.papy.in/bbs/vbnet/200901/09010020.html
https://social.msdn.microsoft.com/Forums/ja-JP/195fcbbe-8fe4-4b1e-aa1f-c9894238c81e/control?forum=netfxgeneralja



ということで修正案。


Option Strict Off
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each txt In Me.Controls.OfType(Of TextBox)()
            AddHandler txt.Leave, AddressOf TextBoxes_Leave
        Next
    End Sub

    Private Sub TextBoxes_Leave(sender As TextBox, e As EventArgs)
        Dim d As Decimal
        If Decimal.TryParse(sender.Text, d) AndAlso d > 0.0d Then
            sender.ResetBackColor()
        Else
            'MsgBox("非数値、または 0 以下の値が入っています。") 
            sender.BackColor = Color.Red
            MsgBox("0 よりも大きい数値を入力してください。")
        End If
    End Sub
End Class
投稿者 (削除されました)  () 投稿日時 2018/5/21 23:53:49
(削除されました)
投稿者 kkkkk   (社会人) 投稿日時 2018/5/21 19:08:43
rvf 様 ありがとうございます。 参考にさせていただきました。

TextBoxが10個あり、0か負の値を入力時にTextBoxの背景が赤色になり、更に0か負の値が入力されたTextBoxにフォーカスが移動するように作りたいのですが、うまく行きません。
下記のコードのどこをいじればいいでしょうか?


  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each ctl As Control In Me.Controls
            If TypeOf ctl Is TextBox  Then
                AddHandler CType(ctl, TextBox).Click, AddressOf TextBox_textbox_leave
            End If
        Next

 Private Sub TextBox_textbox_leave(ByVal sender As System.Object, ByVal e As System.EventArgs)

        If Val(CType(sender,TextBox).Text) <= 0 Then           
    MsgBox("0か負の値がはいっています")

            TextBox1.BackColor = Color.Red         
        Else
            TextBox1.BackColor = Color.White         
        End If



    End Sub
投稿者 (削除されました)  () 投稿日時 2018/5/21 19:03:56
(削除されました)
投稿者 rvf  (社会人) 投稿日時 2018/5/19 12:22:13
CIntじゃなくて?

それはさておきHandlesに全てのテキストボックスを追加し
CInt(CType(sender,TextBox).Text)
とすればいいのではないかと
投稿者 kkkkk  (社会人) 投稿日時 2018/5/19 10:04:35
テキストボックスに文字が入力されたときに負の値が入ったときにメッセージが出るようにするには
下記のようにするといいと思うんですけれども、

    Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
        If CStr(TextBox1.Text) <= 0 Then
            MsgBox("0か負の値がはいっています")
        End If

たとえば、テキストボックスの数がいくつもあってそのすべてに上記のコードを適応させるにはどうすればいいですか?