要求仕様4の実装例
読みやすいように要求仕様4を再掲します。
「2進、8進、10進、16進の4個の数値表現を扱えるようにする」
この仕様を満たすためには、数値表現が切り替わる瞬間に適切な処理をしなければならないので、各オプションボタンのCheckedChangedイベントに処理を実装する必要があります。実装するべき処理は、
- 入力欄に不適切な数値が入力できないようにする
- 既に表示されている数値を適切なものへと変える
の2つです。
この2つの処理を簡単に実装するには2つの準備が必要です。一つは、各数値ボタンの有効化/無効化を効率よく行うためにボタンの配列を用意すること。配列は必ずしも用意する必要はないのですが、配列を使用した方が簡単に実装できます。もう一つは、現在指定されている即値を記録する変数です。この変数についても用意した方が効率よくなります。この2つの変数はCalculatorクラスのフィールドとして宣言します。
Imports VirtualCPU Public Class Calculator Private cpu As IntelCpu Private NumberButtons As List(Of Button) Private inputValue As UInteger '入力欄に指定されている数値 '機械語駆動式関数電卓を正常に動作させるための下準備を行います Private Sub Calculator_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '各種変数の初期化を行う cpu = New IntelCpu() 'コントロールの準備 RegisterCombo.SelectedIndex = 0 ValueCombo.SelectedIndex = 0 NumberButtons = New List(Of Button)() NumberButtons.AddRange(New Button() {NumberButton0, NumberButton1, _ NumberButton2, NumberButton3, NumberButton4, NumberButton5, _ NumberButton6, NumberButton7, NumberButton8, _ NumberButton9, NumberButtonA, NumberButtonB, _ NumberButtonC, NumberButtonD, NumberButtonE, NumberButtonF}) '10進数を標準にする DecimalOption_CheckedChanged(Nothing, EventArgs.Empty) End Sub End Class
これで準備は終了です。CheckedChangedイベントに処理を実装します。まず実装例を掲載してから内容を説明します。
Imports VirtualCPU Public Class Calculator '0と1ボタン以外を無効化し、指定された値を保存します。 Private Sub BinaryOption_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BinaryOption.CheckedChanged '必要な数値ボタンの有効化 If Not NumberButtons Is Nothing Then For i As Integer = 2 To 15 NumberButtons(i).Enabled = False Next End If '指定値値を保存 If Me.BinaryOption.Checked = True Then Me.ValueBox.Text = Convert.ToString(inputValue, 2) Else Try inputValue = Convert.ToUInt32(Me.ValueBox.Text, 2) Catch oe As OverflowException MessageBox.Show("指定できる限界値を超えています。指定しなおしてください。", "入力エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End If '限界桁数を設定 ValueBox.MaxLength = 32 End Sub '0~7までのボタンだけを有効化し、指定された値を保存します。 Private Sub OctOption_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OctOption.CheckedChanged '必要な数値ボタンの有効化 If Not NumberButtons Is Nothing Then For i As Integer = 2 To 7 NumberButtons(i).Enabled = True Next For i As Integer = 8 To 15 NumberButtons(i).Enabled = False Next End If '指定値値を保存 If Me.OctOption.Checked = True Then Me.ValueBox.Text = Convert.ToString(inputValue, 8) Else Try inputValue = Convert.ToUInt32(Me.ValueBox.Text, 8) Catch oe As OverflowException MessageBox.Show("指定できる限界値を超えています。指定しなおしてください。", "入力エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End If '限界桁数を設定 ValueBox.MaxLength = 11 End Sub '0~9までのボタンだけを有効化し、指定された値を保存します。 Private Sub DecimalOption_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DecimalOption.CheckedChanged '必要な数値ボタンを有効化 If Not NumberButtons Is Nothing Then For i As Integer = 2 To 9 NumberButtons(i).Enabled = True Next For i As Integer = 10 To 15 NumberButtons(i).Enabled = False Next End If '指定値値を保存 If Me.ValueBox.Text.Length <> 0 Then If Me.DecimalOption.Checked = True Then Me.ValueBox.Text = Convert.ToString(inputValue, 10) Else Try inputValue = Convert.ToUInt32(Me.ValueBox.Text, 10) Catch oe As OverflowException MessageBox.Show("指定できる限界値を超えています。指定しなおしてください。", "入力エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End If End If '限界桁数を設定 ValueBox.MaxLength = 10 End Sub 'すべてのボタンを有効化と数値表現の変換を行う Private Sub HexOption_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HexOption.CheckedChanged '必要な数値ボタンの有効化 If Not NumberButtons Is Nothing Then For i As Integer = 2 To 15 NumberButtons(i).Enabled = True Next End If '数値表現の変換 If Me.HexOption.Checked = True Then Me.ValueBox.Text = Convert.ToString(inputValue, 16) Else Try inputValue = Convert.ToUInt32(Me.ValueBox.Text, 16) Catch oe As OverflowException MessageBox.Show("指定できる限界値を超えています。指定しなおしてください。", "入力エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End If '限界桁数を設定 ValueBox.MaxLength = 8 End Sub End Sub
少々長いですが、実装内容は簡単ですので安心してください。先ほど述べたように、「入力欄に不適切な数値が入力できないようにする」に対応する処理が必要となります。そのためには余計なボタンが押されないようにしなければなりません。例えば、10進数のオプションがクリックされている時、Fのボタンを押せば数値は変になってしまいます。そのため、各進数に応じたボタンを有効化/無効化する必要があるのです。それが次の部分です。
'必要な数値ボタンを有効化 If Not NumberButtons Is Nothing Then For i As Integer = 2 To 9 NumberButtons(i).Enabled = True Next For i As Integer = 10 To 15 NumberButtons(i).Enabled = False Next End If
ボタンコントロールのEnabledプロパティの値を変えることにより、有効化/無効化を行っています。次に行っている処理は「既に表示されている数値を適切なものへと変える」です。この要件を満たすために、Convertクラスを使用して、数値の文字列化と文字列の数値化を行っています。それは次の部分です。
'数値表現の変換 If Me.HexOption.Checked = True Then Me.ValueBox.Text = Convert.ToString(inputValue, 16) Else Try inputValue = Convert.ToUInt32(Me.ValueBox.Text, 16) Catch oe As OverflowException MessageBox.Show("指定できる限界値を超えています。指定しなおしてください。", "入力エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End If
あらかじめ保存されている数値を他の数値表現に変えてから文字列化するには、Convert.ToString( 数値, 進数の数 )メソッドを呼び出します。その逆の場合は、Convert.ToUInt32( Me.ValueBox.Text, 進数 )で文字列と進数を指定してメソッドを呼び出します。
なお、便利なので限界桁数の設定を実装しました。例外を補足していることに注意してください。数値と文字列の変換はオーバーフローが発生する可能性がありますので必ずチェックする必要があります。
この説明を参考にしながら、再度各CheckedChangedイベントの実装例を読んでください。処理内容がよく分かると思います。
後もう一つ、数値を扱う上でやるべきことがあります。それはValueBoxテキストボックスに関する処理です。それは、テキストボックスのテキスト欄の文字がすべて消された時の対処と、文字を数値へ変換して他の処理の補助をすることです。テキストボックスの欄が0文字の場合、絶対に数値へ変換できません。そこで、必ず0は表示されるようにTextChangedイベントに実装します。次に、現在はオプション切り替え時のみしか文字列の数値化を行っていないので、テキストボックスからフォーカスが外れた際にも変換するようにValidatedイベントに処理を追加します。
それではコードを掲載します。コードをよく読んで、同等の処理が自分の実装で行われているかチェックしてください。
'必ず数値が入力されている状態にします。 Private Sub ValueBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ValueBox.TextChanged Dim btn As Button = CType(sender, Button) If ValueBox.Text.Length <> ValueBox.MaxLength Then ValueBox.Text &= btn.Text End If End Sub '入力された文字を数値へ変換します Private Sub ValueBox_Validated(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ValueBox.Validated If Me.HexOption.Checked = True Then Me.inputValue = Convert.ToUInt32(Me.ValueBox.Text, 16) ElseIf Me.DecimalOption.Checked = True Then Me.inputValue = Convert.ToUInt32(Me.ValueBox.Text, 10) ElseIf Me.OctOption.Checked = True Then Me.inputValue = Convert.ToUInt32(Me.ValueBox.Text, 8) ElseIf Me.BinaryOption.Checked = True Then Me.inputValue = Convert.ToUInt32(Me.ValueBox.Text, 2) End If End Sub
このコードについては特に説明の必要はないと思います。
これで進数の切り替えができるようになり、ボタンを通じて余計な数値を指定できなくなりました。しかしもう一つだけ問題があります。それはValueBoxテストボックスにどんな文字でも入力できてしまうことです。これを防ぐには、キーを押した際に発生するKeyPressイベントで対処します。
'有効な数値だけを受け付けるようにします Private Sub ValueBox_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles ValueBox.KeyPress '無効なキーだと仮定します e.Handled = True '有効なキーなのか判定します If e.KeyChar = vbBack Then 'バックスペースを有効にする e.Handled = False ElseIf Me.BinaryOption.Checked = True Then '2進数が選択されている場合のチェック If (e.KeyChar = "0"c Or e.KeyChar = "1"c) Then e.Handled = False End If ElseIf Me.OctOption.Checked = True Then '8進数が選択されている場合のチェック If (e.KeyChar >= "0"c And e.KeyChar <= "7"c) Then e.Handled = False End If ElseIf Me.DecimalOption.Checked = True Then '10進数が指定されている場合のチェック If (e.KeyChar >= "0"c And e.KeyChar <= "9"c) Then e.Handled = False End If ElseIf Me.HexOption.Checked = True Then '16進数が選択されている場合のチェック If (e.KeyChar >= "0"c And e.KeyChar <= "9"c) Or _ (e.KeyChar >= "A"c And e.KeyChar <= "F") Or _ (e.KeyChar >= "a"c And e.KeyChar <= "f") Then e.Handled = False End If End If End Sub
この実装例でしていることは、入力されたキーが選択されている進数に相応しいものか判定し、適切なキーの場合HandledプロパティをFalseにすることです。この処理によりキーを許可しています。Trueならば許可すると間違いがちですが、Falseが許可の指定なのでこの点に注意してください。
以上で仕様4の実装を完了しました。次は、仕様5・6・7の実装例を解説します。
