初心者がExcel VBAで電卓アプリを作成してみた【Excel】

Excel VBA

今回はいつもと趣向を変えて、Excel VBAに挑戦してみます。
普段はプログラミング言語はPythonを使っているのですが、VBAを使わなければならない機会があり、勉強がてらちょっと挑戦してみました。

これまでVBAの勉強はしたことがなく、業務で他の方の組んだものを必要に迫られて何回かいじった程度で、なんならExcel関数もXLOOKUP関数が使えるくらいで鼻を高くしているような人間ですので、変なところが多いかも知れませんがご容赦ください。・・・と念のため予防線を張っておきます。

概要

要件定義

個人開発ですので設計とかはテキトーですが、抑えるべきポイントはこんな感じでしょう。

  • ボタン(0~9の数字、四則演算子、イコール、クリア)を用意する
  • 計算結果の表示画面を用意する
  • 入力する数字は文字列だが、計算時は数値となる
    (例)2, 3と入力したときに2と3という数値ではなく23という文字列として認識させる
  • 四則演算・イコール・クリア用の処理を用意する
  • 0では割れない。

実際の開発現場では怒られそうな要件定義(機能要件)ですが、まあいいでしょう。
ちなみに非機能要件は今回どうでもいいので追求しません。

設計(デザイン)

Excelはボタンが任意で配置できるのが素晴らしいですよね。
ということでワーッと配置してみました。見た目がショボいのは気にせず進みます。

1行目は結果表示欄です。
開発者の約10割がキライなセル結合をしています。

ボタンを適当に配置

ここまでくれば、あとはVBAを組むだけですね。
内部設計とかは面倒なので飛ばします。

VBAコード

コード全体

以下、作成したコードです。

Option Explicit

' グローバル変数
Private currentInput As String
Private previousInput As String
Private currentOperator As String
Private isNewCalculation As Boolean

' 数値ボタンクリック時の処理
Public Sub NumberClick(number As Integer)
    If isNewCalculation Then
        currentInput = ""
        isNewCalculation = False
    End If
    currentInput = currentInput & CStr(number)
    UpdateDisplay
End Sub

' 演算子ボタンクリック時の処理
Public Sub OperatorClick(operator As String)
    If currentInput <> "" Then
        If previousInput <> "" Then
            CalculateResult
        Else
            previousInput = currentInput
        End If
        currentOperator = operator
        currentInput = ""
    End If
    UpdateDisplay
End Sub

' イコールボタンクリック時の処理
Public Sub EqualClick()
    If currentInput <> "" And previousInput <> "" And currentOperator <> "" Then
        CalculateResult
        isNewCalculation = True
    End If
    UpdateDisplay
End Sub

' クリアボタンクリック時の処理
Public Sub ClearClick()
    currentInput = ""
    previousInput = ""
    currentOperator = ""
    isNewCalculation = False
    UpdateDisplay
End Sub

' 計算実行
Private Sub CalculateResult()
    Dim result As Double
    Select Case currentOperator
        Case "+"
            result = CDbl(previousInput) + CDbl(currentInput)
        Case "-"
            result = CDbl(previousInput) - CDbl(currentInput)
        Case "*"
            result = CDbl(previousInput) * CDbl(currentInput)
        Case "/"
            If CDbl(currentInput) <> 0 Then
                result = CDbl(previousInput) / CDbl(currentInput)
            Else
                MsgBox "0で除算することはできません。", vbExclamation, "エラー"
                ClearClick
                Exit Sub
            End If
    End Select
    currentInput = CStr(result)
    previousInput = ""
    currentOperator = ""
End Sub

' 表示更新
Private Sub UpdateDisplay()
    Sheet1.Range("B2").Value = currentInput
End Sub

' 以下、ボタン用マクロ
Public Sub Button_0()
    NumberClick 0
End Sub

Public Sub Button_1()
    NumberClick 1
End Sub

Public Sub Button_2()
    NumberClick 2
End Sub

Public Sub Button_3()
    NumberClick 3
End Sub

Public Sub Button_4()
    NumberClick 4
End Sub

Public Sub Button_5()
    NumberClick 5
End Sub

Public Sub Button_6()
    NumberClick 6
End Sub

Public Sub Button_7()
    NumberClick 7
End Sub

Public Sub Button_8()
    NumberClick 8
End Sub

Public Sub Button_9()
    NumberClick 9
End Sub

Public Sub Button_Plus()
    OperatorClick "+"
End Sub

Public Sub Button_Minus()
    OperatorClick "-"
End Sub

Public Sub Button_Multiply()
    OperatorClick "*"
End Sub

Public Sub Button_Divide()
    OperatorClick "/"
End Sub

Public Sub Button_Equal()
    EqualClick
End Sub

Public Sub Button_Clear()
    ClearClick
End Sub

ボタン用マクロを各ボタンにチマチマ適用していけば終了です。

簡単な解説

ザーッとかいつまんで説明します。

おまじない

これはおまじないらしいです。
変数は宣言しなければダメよ、という意味で、未宣言(未定義)の変数の使用を防ぐようです。

Option Explicit

変数宣言

今回は以下4つの変数を使います。

' グローバル変数
Private currentInput As String
Private previousInput As String
Private currentOperator As String
Private isNewCalculation As Boolean

それぞれの役割はこんな感じです。

  • currentInput: 現在入力値。現在入力されている数値を保持する
  • previousInput: 前回入力値。前回の入力された数値を保持する
  • currentOperator: 現在の演算子(+, -, *, /)を保持する
  • isNewCalculation: 計算ステータス。新しい計算が開始されたかどうかを示す

currentInputとpreviousInputで分けているのは、a+bの計算時にaが空文字列のままbを入力しておかしなことになるみたいなことを防ぐなどの目的があります。

まとめたい方はまとめてもいいと思いますが、こういうのは分けるのが定跡なのであまりオススメはできません。

数字ボタンクリック時の処理

数字ボタンがクリックされたときの処理内容です。
入力された数字を結合しているだけです。

Public Sub NumberClick(number As Integer)
    If isNewCalculation Then
        currentInput = ""
        isNewCalculation = False
    End If
    currentInput = currentInput & CStr(number)
    UpdateDisplay
End Sub

“(number As Integer)"の部分から分かるように、整数を引数としています。

計算開始時(isNewCalculation = True)に、現在入力値(currentInput)を""とし、計算ステータスを計算中(isNewCalculation = False)とします。

また、現在入力値に整数の引数(押下された数字)を文字列結合して、電卓の表示画面を更新します。

演算子ボタンクリック時の処理

演算子ボタンがクリックされたときの処理内容です。
条件分岐がネストしていて嫌悪感を抱く方もいるかもしれませんが、今入力している数字があれば、それを前の数字として保存し、どの演算子を使うかを設定しているだけです。

Public Sub OperatorClick(operator As String)
    If currentInput <> "" Then
        If previousInput <> "" Then
            CalculateResult
        Else
            previousInput = currentInput
        End If
        currentOperator = operator
        currentInput = ""
    End If
    UpdateDisplay
End Sub

“(operator As String)"の部分から分かるように、文字列(+, -, *, /)を引数としています。

現在入力値(currentInput)および前回入力値(previousInput)が空でない場合、演算を実行(後述のCalculateResult関数)します。
前回入力値が空の場合は、前回入力値に現在入力値を代入します。

現在入力値が空の場合は続けて、文字列の引数(押下された演算子)をcurrentOperatorにセットし、現在入力値を空にします。

最後に、電卓の表示画面を更新します。

イコールボタンクリック時の処理

イコールボタンがクリックされたときの処理内容です。
計算に必要な数字と記号が揃っていたら、計算を実行します。
“a+b"なら"a"も"+"も"b"もあればOKってことです。

Public Sub EqualClick()
    If currentInput <> "" And previousInput <> "" And currentOperator <> "" Then
        CalculateResult
        isNewCalculation = True
    End If
    UpdateDisplay
End Sub

現在入力値(currentInput)、前回入力値(previousInput)、演算子(currentOperator)が空でない場合、計算を実行し、計算ステータスを終了(isNewCalculation = True)します。

最後に、電卓の表示画面を更新します。

クリアボタンクリック時の処理

クリアボタンがクリックされたときの処理内容です。
すべての入力をリセットするだけです。

Public Sub ClearClick()
    currentInput = ""
    previousInput = ""
    currentOperator = ""
    isNewCalculation = False
    UpdateDisplay
End Sub

計算実行

最もミソな部分ですね。

Private Sub CalculateResult()
    Dim result As Double
    Select Case currentOperator
        Case "+"
            result = CDbl(previousInput) + CDbl(currentInput)
        Case "-"
            result = CDbl(previousInput) - CDbl(currentInput)
        Case "*"
            result = CDbl(previousInput) * CDbl(currentInput)
        Case "/"
            If CDbl(currentInput) <> 0 Then
                result = CDbl(previousInput) / CDbl(currentInput)
            Else
                MsgBox "0で除算することはできません。", vbExclamation, "エラー"
                ClearClick
                Exit Sub
            End If
    End Select
    currentInput = CStr(result)
    previousInput = ""
    currentOperator = ""
End Sub

まず、resultという変数をDouble型で宣言します。
これが計算結果にあたります。

次に、Select Case文を使って、演算子(currentOperator)によって異なる処理を実行します。
現在入力値(currentInput)、前回入力値(previousInput)ともに文字列型なので、CDblでDouble型に変換し、四則演算した結果をresultに代入します。

ただし、割り算の際は0で割るとエラーが出力されるよう、条件分岐を入れています。

最後に、計算が終わったら、次の計算でも結果を使えるように、resultを文字列型に変換してからcurrentInputに代入します。

また、現在入力値と前回入力値は空にしておきます。

表示更新

計算結果を表示する処理です。

Private Sub UpdateDisplay()
    Sheet1.Range("A1").Value = currentInput
End Sub

今回はSheet1のA1セル(結合していますがA1で大丈夫です)に、現在入力値を表示します。

ボタン用マクロ

ソースコードは割愛しますが、それぞれ上述のNumberClick関数やOperatorClick関数に引数をあてて実行しているだけです。
EqualClick関数やClearClick関数はボタン用に関数を作らず、そのまま使っても大丈夫です。

結果

GIF化する際に色合いがおかしなことになってしまいましたが、挙動はこんな感じになりました。

VBA初学者にしては良い出来栄えな気がします。

ただ、設計が甘かったため、複数演算には対応しきれていません。
“a+b="なら問題ないのですが、"a+b+c="とすると途端に言うことを聞かなくなるので、改良が必要ですね。

Excel VBAというと、Pythonと比べて変数を宣言する必要があったり、良くも悪くもExcelのことを知らなければならなかったりと、敷居が高いイメージがありましたが、触ってみると意外と楽しかったです。

今後もVBA触ってみようと思います。

以上です。

スポンサーリンク

Excel VBA

Posted by このめ