SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

VB.NETで学ぶ機械語の基礎

VB.NETで仮想CPUを作ろう(13)
- 機械語駆動式 関数電卓を作ろう! 解答編(前半)

VB.NETで学ぶ機械語の基礎 第13回

ダウンロード VirtualCPU13.zip (448.7 KB)

要求仕様4の実装例

 読みやすいように要求仕様4を再掲します。

 「2進、8進、10進、16進の4個の数値表現を扱えるようにする」

 この仕様を満たすためには、数値表現が切り替わる瞬間に適切な処理をしなければならないので、各オプションボタンのCheckedChangedイベントに処理を実装する必要があります。実装するべき処理は、

  1. 入力欄に不適切な数値が入力できないようにする
  2. 既に表示されている数値を適切なものへと変える

の2つです。

 この2つの処理を簡単に実装するには2つの準備が必要です。一つは、各数値ボタンの有効化/無効化を効率よく行うためにボタンの配列を用意すること。配列は必ずしも用意する必要はないのですが、配列を使用した方が簡単に実装できます。もう一つは、現在指定されている即値を記録する変数です。この変数についても用意した方が効率よくなります。この2つの変数はCalculatorクラスのフィールドとして宣言します。

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イベントに処理を実装します。まず実装例を掲載してから内容を説明します。

各オプションボタンの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のボタンを押せば数値は変になってしまいます。そのため、各進数に応じたボタンを有効化/無効化する必要があるのです。それが次の部分です。

ボタンの有効化/無効化(10進数の場合)
'必要な数値ボタンを有効化
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クラスを使用して、数値の文字列化と文字列の数値化を行っています。それは次の部分です。

数値の文字列化&文字列の数値化(16進数の場合)
'数値表現の変換
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イベントに処理を追加します。

 それではコードを掲載します。コードをよく読んで、同等の処理が自分の実装で行われているかチェックしてください。

ValueBox(テキストボックスに関するイベント)
'必ず数値が入力されている状態にします。
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の実装例を解説します。

次のページ
仕様5・6・7の実装例

この記事は参考になりましたか?

VB.NETで学ぶ機械語の基礎連載記事一覧

もっと読む

この記事の著者

インドリ(インドリ)

分析・設計・実装なんでもありのフリーエンジニア。ブログ「無差別に技術をついばむ鳥(http://indori.blog32.fc2.com/)」の作者です。アドバイザーをしたり、システム開発したり、情報処理技術を研究したりと色々しています。座右の銘は温故知新で、新旧関係なく必要だと考えたものは全て学...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3424 2010/04/27 12:04

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー