if文 比較対象が3つ

タグの編集
投稿者 uuu  (社会人) 投稿日時 2018/5/22 19:11:16
下記のように3つの比較をしたいのですが、できません。
教えていただけないでしょうか?

if  a>b>c then 
処理
end if

実行すると
if  a>bになっています
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/5/23 01:25:08
こういう場合には
If a > b AndAlso b > c Then
のように記述します。


> 実行すると
> if  a>bになっています 

『If a > b > c Then』という演算は、
『If (a > b) > c Then』の順で評価されます。

そして (a > b) の結果は、True または False になるため、これは即ち
 『If True > c Then』
 『If False > c Then』
のいずれかの意味になるわけです。

このとき、c のデータ型が Boolean だった場合には、
常に Else 句が実行されることになるはずです。
(VB においては、True よりも False の方が大きな値として扱われるため)

一方、c がもしも Integer だった場合、そこで暗黙の型変換が実行されます。
たとえば 『If CInt(a > b) > c Then』 相当という具合に。

そして、CInt(True) は -1、CInt(False) は 0 にあたりますので、
下記の実行結果は、Option Strict Off なら「真」、Option Strict On なら「エラー」扱いです。

Dim a As Integer = +2
Dim b As Integer = 0
Dim c As Integer = -2
If a > b > c Then
投稿者 uuu  (社会人) 投稿日時 2018/5/23 22:12:30
途中でわからなくなったので、教えてください
a,b,cのテキストボックスが3つあります。
入力する値の大きさは下記が条件です
 a>b>c

教えていただいた
If a > b AndAlso b > c Then
は a>cも含まれているでしょうか?

またテキストボックスに入力時に3つの関係が不適切ならメッセージを出すようにしたいです。
例えばb>aなら下記みたいなイメージです

   If Val(TextBox2.Text) > Val(TextBox1.Text) Then

  MsgBox("bはaより小さいです")

これをc>b>aで、まとめて比較し、できるようにしたいです

ただこれだけだと、TextBox2.Text入力後、違うテキストボックスに入力しようとするとメッセージが出てしまいます。

対策として下記で対応しているんですけど、問題はありませんか?

       If TextBox2.TextLength <> 0 AndAlso TextBox1.TextLength <> 0 Then

現状はこのようになっています。
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each q In Me.Controls.OfType(Of TextBox)()
            AddHandler q.Leave, AddressOf TextBoxes_Leave
        Next
    End Sub
    Private Sub TextBoxes_Leave(sender As TextBox, e As EventArgs)
        Dim d As Double

        If Double.TryParse(sender.Text, d) AndAlso d > 0 Then
            sender.ResetBackColor()

            If TextBox2.TextLength <> 0 AndAlso TextBox1.TextLength <> 0 Then

                If Val(TextBox2.Text) > Val(TextBox1.Text) Then

                    MsgBox("bはaより小さいです")
                    sender.BackColor = Color.Red
                    sender.Focus()


                End If

            ElseIf TextBox3.TextLength <> 0 AndAlso TextBox2.TextLength <> 0 Then

                If Val(TextBox3.Text) > Val(TextBox2.Text) Then

                    MsgBox("cはbより小さいです")
                    sender.BackColor = Color.Red
                    sender.Focus()


                ElseIf TextBox3.TextLength <> 0 AndAlso TextBox1.TextLength <> 0 Then

                    If Val(TextBox3.Text) > Val(TextBox1.Text) Then

                        MsgBox("cはaより小さいです")
                        sender.BackColor = Color.Red
                        sender.Focus()
                    End If

                End If
            End If
        End If
    End Sub

コードがものすごく長いので短くもしたいです。




投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/5/24 04:52:12
kkkkk さんと uuu さんは同じ方でしょうか?
別の質問とはいえ、内容が酷似しているようなので。


> 教えていただいた
> If a > b AndAlso b > c Then
> は a>cも含まれているでしょうか?

はい。たとえば a, b, c いずれもが Integer 値だとすれば、
a > b かつ b > c であるにも関わらず、
a > c にならない(つまり a ≦ c である)ような数はありえませんよね。

数学的に言えば、 (a > b) ∧ (b > c) の関係を意味しますので、
それが (a > c) の関係であることも自明となります。


厳密に言ってしまえば、言語仕様的には
 If a > b AndAlso b > c AndAlso a > c Then
 If a > b AndAlso b > c Then
の 2 つの結果が異なる結果になることも、一応ありえなくはなかったりします。
とはいえそれは非常に特殊なケースに限られますので、
通常はそこまで考えなくて良いでしょう。


> If Val(TextBox2.Text) > Val(TextBox1.Text) Then
Val の利用はおすすめしません。(エラーになりえるので)

せっかく TryParse メソッドを利用しているのですから、
それで変換した値を使うべきでしょう。


> 対策として下記で対応しているんですけど、問題はありませんか?
問題があると思いますよ。

強制的にフォーカスを当てなおしているのが、あまり良くないですが、
それ以上に、テキストの内容が『』や『XYZ』や『0』や『-123』だった場合の
処置が抜けているのが問題ですし、sender と TextBox1~3 の組み合わせも不自然です。


また、a, b, c の 3 個所のうち、2 個所の修正が必要な場合において、
そのうちの 1 個所を編集すると、一時的に大小関係が崩れてしまい、
2 個所目の編集が始められないといったパターンが起こりそうです。


極端な話、初期状態でのフォーカス位置と TextBox の値が下記のようになっていた場合、
提示頂いたコードだと、a(TextBox1) と b(TextBox2) の比較でメッセージが表示されるのに、
それとは無関係のはずの c(TextBox3)が赤くなり、a や b を訂正しようとしても
阻害されてしまうことになると思います。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    For Each q In Me.Controls.OfType(Of TextBox)()
        AddHandler q.Leave, AddressOf TextBoxes_Leave
    Next
    TextBox1.Text = "10"
    TextBox2.Text = "20"
    TextBox3.Text = "30"
    ActiveControl = TextBox3
End Sub



そもそも、今回の仕様が
・どういう時に赤くなってほしいのか
・赤から標準色に戻すのはどういう時か
・Leave したコントロール以外が赤になってほしいパターンがあるのか
・Leave したコントロール以外を標準色に戻したいパターンがあるのか
・「空欄時」「非数値の時」「マイナス値の時」「0 の時」とで、対処を変える必要があるのか否か
などが曖昧なので、どういう動作を求めているのかを、
より細かく確認しなおすのが先決かと思います。


> またテキストボックスに入力時に3つの関係が不適切ならメッセージを出すようにしたいです。

「3 つの関係」を調査しなければならないのに、1 つのボックスの Leave 時に
即時検査する画面設計にしているのが、話を複雑化しているように思います。

こういう場合には、入力後即時に検査するのではなく、値を確定するタイミングを
後回しにするという手法が良く利用されます。

たとえば、ファイルを右クリックしてプロパティを表示させた場合、
[全般]タブでファイル名を変更できるようになっていますが、ここで、
ファイル名のテキストボックスを空にしたり、ファイル名として利用できない文字を
入力したとしても、それだけでは直ちにエラーメッセージが表示されることはありません。

この場合、ファイル名の入力値検査は、プロパティ ダイアログの
[OK]ボタンを押したタイミングで行われるようになっています。


なのでそれを真似て、Leave 時あるいは Validating 時に検査するのは、
「現在のボックスに正数がセットされたか」のみに限定してしまい、
各ボックスの大小判定は、ボタンクリック時などといった
別のタイミングで検証した方が良いのではないでしょうか。


仮に、ユーザー入力の問題をその場で指摘した方がよい仕様だったとしても、
モーダルのメッセージなどを用いるのではなく、こういう場合には
インプレースエラー表示(たとえば ErrorProvider を利用した表現)や、
モードレスのエラー処理(たとえば Tooltip のバルーンモード) の利用を
検討した方が、うまくいくかもしれません。
https://msdn.microsoft.com/ja-jp/library/aa511267.aspx#presentation

MsgBox などといったモーダルのエラー処理を行うと、エラーメッセージを閉じるまで、
値の再入力ができなくなるので、連続した入力を阻害する結果になりえます。
投稿者 uuu   (社会人) 投稿日時 2018/5/24 19:17:50
仕様は
・どういう時に赤くなってほしいのか  a>b>cの関係が成り立っていないときです
・赤から標準色に戻すのはどういう時 a>b>cの関係が成り立っているときです
・Leave したコントロール以外が赤になってほしいパターンがあるのか ないです
・Leave したコントロール以外を標準色に戻したいパターンがあるのか ないです
・「空欄時」「非数値の時」「マイナス値の時」「0 の時」とで、対処を変える必要があるのか否か いまのところは練習のためなしです。

今はa>b>cの関係だけに注目し作っています。

>なのでそれを真似て、Leave 時あるいは Validating 時に検査するのは、
>「現在のボックスに正数がセットされたか」のみに限定してしまい、
>各ボックスの大小判定は、ボタンクリック時などといった
>別のタイミングで検証した方が良いのではないでしょうか。

判定はボタンクリック時に変更しました。
これも実施しているのですが、うまくいきません。

If a > b AndAlso b > c Then

で実施しているのですが、3個に入力後にどれか1つ値を変化させると、a>b>cの関係性が崩れても
msgを出さないようになってしまっています
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/5/25 11:27:43
> 今はa>b>cの関係だけに注目し作っています。

c が最小値となるべきなのですよね。

仮に、kkkkk さん= uuu さんだとしたら、この条件は
 a > b > c > 0
が正しいのでは無いでしょうか。


また、「数値しか入力させない」という前提で開発するのであれば、
そもそも TextBox1.Text を使うべきではなく、
NumericUpDown1.Value を使った方が楽でしょう。

NumericUpDown なら、必ず数値が入力されることになるので、
非数値が入力されることを考慮せず、a / b / c の大小判定のみに専念できますし、
NumericUpDown の DecimalPlaces と Minimum プロパティを適切にセットしておけば、
そもそも 0 以下の値が入力されることさえ防げます。


もしも TextBox で続けるのであれば、
>> ・「空欄時」「非数値の時」「マイナス値の時」「0 の時」とで、対処を変える必要があるのか否か
という入力が発生することは防げないので、そのときの対処は決めておかねばならず、
> いまのところは練習のためなしです。
と逃げるわけには行かなくなります。

とはいえ、もしも上記の 4 種を区別しないのであれば、
とりあえず簡単なのは、こんな実装ですかね。

Dim a, b, c As Decimal
Decimal.TryParse(TextBox1.Text, a)
Decimal.TryParse(TextBox2.Text, b)
Decimal.TryParse(TextBox3.Text, c)

If a > b AndAlso b > c AndAlso c > 0D Then
 TextBox1.ResetBackColor()
 TextBox2.ResetBackColor()
 TextBox3.ResetBackColor()
 
 '正しい値が得られたので、a,b,cを使った処理をここに記述 
 
Else
 '正しい入力ではない 
 TextBox1.BackColor = Color.Red
 TextBox2.BackColor = Color.Red
 TextBox3.BackColor = Color.Red
 MsgBox("a>b>c>0な入力になっていません")
 Return
End If