今日は、「ExcelVBAで電卓を作ろう」の3回目です。
バックナンバーは、以下の通りです。
第1回「複数のコントロールのイベントを一つのプロシージャにまとめる(ExcelVBA)」
第2回「ExcelVBAで電卓を作ろう-その2「アルゴリズムを考える」」
さて、前回のアルゴリズムを踏まえて、今回は、実際にコードを書いてみましょう。
まず、電卓の確認です。
問題をシンプルにするために、0~9の数字と、加減乗除のボタン、=ボタン、それにAC(オールクリア)ボタンのみの
構成にします。
それでは、コーディングしましょう。
第1回の際に、数字のボタンを押すと、数字が表示されるコードを書きましたね。
そうです。Classモジュールに記述しましたね。まず、これを少し、修正しましょう。
実は、このままでは、常に1桁の数字しか表示できないのです。
2ケタ以上表示できるように、以下の様に修正します。
Option Explicit
'イベントを持つコマンドボタン型の変数を宣言
Private WithEvents Btn As MSForms.CommandButton
'ボタンの数字を格納する変数を宣言
Private Index As Integer
Public Sub NewClass(ByVal c As MSForms.CommandButton, _
ByVal i As Integer)
'いわゆるコンストラクタ処理
'引数のコマンドボタンを変数に格納
Set Btn = c
'コマンドボタンの数字を変数に格納
Index = i
End Sub
Private Sub Btn_Click()
'数字のボタン(0~9)を押した時の処理
'frmCalcフォームのTextBox1に、
'変数Indexの中身を表示する
If IsNew Then
'数字の新規入力時
frmCalc.TextBox1.Text = Index
Else
'数字の入力途中
frmCalc.TextBox1.Text = _
CLng(frmCalc.TextBox1.Text & Index)
End If
'数字の入力途中にする
IsNew = False
End Sub
画像も載せておきます。
変更箇所は、Private Sub Btn_Click() のコードだけです。
IsNew という変数が登場しました。
この変数は、True と False の2種類の値をとることができるブーリアン(Boolean)型の変数です。
この変数にTrueが格納されている場合は、新規入力とします。
つまり、今までの数字は、無視して、最初に入力される数字ということです。
加減乗除のボタンと、=ボタン、ACボタンが押された直後に、Trueが格納されます。
数字の入力直後で、IsNew に Falseを格納します。
これで、2桁以上の数字の表示が可能となります。
なお、このIsNew という変数は、ユーザーフォームからもこのClassモジュールからも使用します。
従って、どのモジュールからも使用できるように、標準モジュールに宣言を記述します。
「挿入」→「標準モジュール」とクリックします。
以下のように記述します。
Option Explicit
Public IsNew As Boolean
Public Sub ShowCalc()
frmCalc.Show
End Sub
画像はこちら。
変数の宣言の他に、フォームを起動するプロシージャ「ShowCalc」も書いておきました。
それでは、いよいよ、フォームにコードを書いていきます。
ユーザーフォームのコードウィンドウを表示します。
冒頭に変数の宣言と列挙型の宣言、そして、フォームの初期化イベントのコードを書きます。
Option Explicit
Private NumBtn(0 To 9) As New Class1
Private stack(0 To 1) As Currency
Private Action As Integer
Private Enum Act
Equal
Plus
Minus
Multi
Devi
End Enum
Private Sub UserForm_Initialize()
'インスタンスの生成
Dim i As Integer
For i = 0 To 9
NumBtn(i).NewClass Controls("b" & i), i
Next
'表示設定
TextBox1.Text = 0
'初期化処理
InitCalc
End Sub
UserForm_Initialize プロシージャの中の InitCalc は、サブプロシージャです。
別途、以下の様に書いておきます。
Private Sub InitCalc()
'初期化処理
'スタックと記号の初期化
stack(0) = 0
stack(1) = 0
Action = Act.Plus
'表示クリアフラグの初期化
IsNew = True
End Sub
つまり、計算用の配列の値を0にして、記号を格納するAction変数にプラスを意味する数字を代入します。
(ここで、単なる数字の代わりに列挙型を使用しています)
さらに、IsNew 変数にTrueを代入して、新規入力を促しています。
以上、参考までに画像です。
さて、それでは、ここで、記号ボタンを押したときの処理を書いてみましょう。
この処理は、加減乗除の4つのボタンと、=ボタンを押したときに、いつでも呼び出されるプロシージャとして記述します。
何度も同じコードを書く必要がなくなりますね。
以下のように書きます。
Private Sub Calc(ByVal CurrentAction As Integer)
'計算処理(記号ボタンが押されると呼び出される)
'電卓窓の数字を変数に格納
Dim n As Long
n = CLng(TextBox1.Text)
stack(1) = n
'計算結果を格納する変数
Dim Ans As Double
Select Case Action
Case Act.Equal
'=
Action = Act.Equal
Case Act.Plus
'+
Ans = stack(0) + stack(1)
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
Case Act.Minus
'-
Ans = stack(0) - stack(1)
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
Case Act.Multi
'*
Ans = stack(0) * stack(1)
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
Case Act.Devi
'/
If stack(1) = 0 Then
Ans = 0
Else
Ans = stack(0) / stack(1)
End If
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
End Select
'引数で受け取った記号を格納
Action = CurrentAction
'新規入力にする
IsNew = True
End Sub
画像はこちら。
前回の記事をご覧いただければ、今回のコードの意味もお分かりいただけるでしょう。
このプロシージャは、引数を1つ持っています。
どの記号が押されたのかを引数に指定するのです。
この記号を、Action変数に格納するためです。
さあ、あとは、記号のボタンのコードだけです。
記号のボタンのイベントプロシージャを以下のように記述してみましょう。
Private Sub Plus_Click()
'足し算
'サブプロシージャの呼び出し
Calc Act.Plus
End Sub
Private Sub Minus_Click()
'引き算
'サブプロシージャの呼び出し
Calc Act.Minus
End Sub
Private Sub Multi_Click()
'掛け算
'サブプロシージャの呼び出し
Calc Act.Multi
End Sub
Private Sub Dev_Click()
'割り算
'サブプロシージャの呼び出し
Calc Act.Devi
End Sub
Private Sub btnEnter_Click()
'=の処理
'サブプロシージャの呼び出し
Calc Act.Equal
End Sub
画像も載せておきましょう。
いずれも、サブプロシージャを呼んでいるだけです。
その際、引数にその記号を指定していることに注意してください。
最後に、ACボタンのコードを書いておきましょう。
Private Sub btnAC_Click()
'ACボタンの処理
TextBox1.Text = 0
'初期化処理
InitCalc
End Sub
まさに、オールクリアですね。
それでは、実行してみてください。
いかがですか? 実際の電卓と同様の動作をするでしょう。
色々と試してみてください。
なかには、不思議な処理をする時があるかもしれません。
その理由を考えてみてください。
修正してみるのも勉強になります。
エクセルのバージョンは、2002(XP)以上でお願いします。
だい
バックナンバーは、以下の通りです。
第1回「複数のコントロールのイベントを一つのプロシージャにまとめる(ExcelVBA)」
第2回「ExcelVBAで電卓を作ろう-その2「アルゴリズムを考える」」
さて、前回のアルゴリズムを踏まえて、今回は、実際にコードを書いてみましょう。
まず、電卓の確認です。
問題をシンプルにするために、0~9の数字と、加減乗除のボタン、=ボタン、それにAC(オールクリア)ボタンのみの
構成にします。
それでは、コーディングしましょう。
第1回の際に、数字のボタンを押すと、数字が表示されるコードを書きましたね。
そうです。Classモジュールに記述しましたね。まず、これを少し、修正しましょう。
実は、このままでは、常に1桁の数字しか表示できないのです。
2ケタ以上表示できるように、以下の様に修正します。
Option Explicit
'イベントを持つコマンドボタン型の変数を宣言
Private WithEvents Btn As MSForms.CommandButton
'ボタンの数字を格納する変数を宣言
Private Index As Integer
Public Sub NewClass(ByVal c As MSForms.CommandButton, _
ByVal i As Integer)
'いわゆるコンストラクタ処理
'引数のコマンドボタンを変数に格納
Set Btn = c
'コマンドボタンの数字を変数に格納
Index = i
End Sub
Private Sub Btn_Click()
'数字のボタン(0~9)を押した時の処理
'frmCalcフォームのTextBox1に、
'変数Indexの中身を表示する
If IsNew Then
'数字の新規入力時
frmCalc.TextBox1.Text = Index
Else
'数字の入力途中
frmCalc.TextBox1.Text = _
CLng(frmCalc.TextBox1.Text & Index)
End If
'数字の入力途中にする
IsNew = False
End Sub
画像も載せておきます。
変更箇所は、Private Sub Btn_Click() のコードだけです。
IsNew という変数が登場しました。
この変数は、True と False の2種類の値をとることができるブーリアン(Boolean)型の変数です。
この変数にTrueが格納されている場合は、新規入力とします。
つまり、今までの数字は、無視して、最初に入力される数字ということです。
加減乗除のボタンと、=ボタン、ACボタンが押された直後に、Trueが格納されます。
数字の入力直後で、IsNew に Falseを格納します。
これで、2桁以上の数字の表示が可能となります。
なお、このIsNew という変数は、ユーザーフォームからもこのClassモジュールからも使用します。
従って、どのモジュールからも使用できるように、標準モジュールに宣言を記述します。
「挿入」→「標準モジュール」とクリックします。
以下のように記述します。
Option Explicit
Public IsNew As Boolean
Public Sub ShowCalc()
frmCalc.Show
End Sub
画像はこちら。
変数の宣言の他に、フォームを起動するプロシージャ「ShowCalc」も書いておきました。
それでは、いよいよ、フォームにコードを書いていきます。
ユーザーフォームのコードウィンドウを表示します。
冒頭に変数の宣言と列挙型の宣言、そして、フォームの初期化イベントのコードを書きます。
Option Explicit
Private NumBtn(0 To 9) As New Class1
Private stack(0 To 1) As Currency
Private Action As Integer
Private Enum Act
Equal
Plus
Minus
Multi
Devi
End Enum
Private Sub UserForm_Initialize()
'インスタンスの生成
Dim i As Integer
For i = 0 To 9
NumBtn(i).NewClass Controls("b" & i), i
Next
'表示設定
TextBox1.Text = 0
'初期化処理
InitCalc
End Sub
UserForm_Initialize プロシージャの中の InitCalc は、サブプロシージャです。
別途、以下の様に書いておきます。
Private Sub InitCalc()
'初期化処理
'スタックと記号の初期化
stack(0) = 0
stack(1) = 0
Action = Act.Plus
'表示クリアフラグの初期化
IsNew = True
End Sub
つまり、計算用の配列の値を0にして、記号を格納するAction変数にプラスを意味する数字を代入します。
(ここで、単なる数字の代わりに列挙型を使用しています)
さらに、IsNew 変数にTrueを代入して、新規入力を促しています。
以上、参考までに画像です。
さて、それでは、ここで、記号ボタンを押したときの処理を書いてみましょう。
この処理は、加減乗除の4つのボタンと、=ボタンを押したときに、いつでも呼び出されるプロシージャとして記述します。
何度も同じコードを書く必要がなくなりますね。
以下のように書きます。
Private Sub Calc(ByVal CurrentAction As Integer)
'計算処理(記号ボタンが押されると呼び出される)
'電卓窓の数字を変数に格納
Dim n As Long
n = CLng(TextBox1.Text)
stack(1) = n
'計算結果を格納する変数
Dim Ans As Double
Select Case Action
Case Act.Equal
'=
Action = Act.Equal
Case Act.Plus
'+
Ans = stack(0) + stack(1)
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
Case Act.Minus
'-
Ans = stack(0) - stack(1)
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
Case Act.Multi
'*
Ans = stack(0) * stack(1)
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
Case Act.Devi
'/
If stack(1) = 0 Then
Ans = 0
Else
Ans = stack(0) / stack(1)
End If
stack(0) = Ans
stack(1) = 0
TextBox1.Text = Ans
End Select
'引数で受け取った記号を格納
Action = CurrentAction
'新規入力にする
IsNew = True
End Sub
画像はこちら。
前回の記事をご覧いただければ、今回のコードの意味もお分かりいただけるでしょう。
このプロシージャは、引数を1つ持っています。
どの記号が押されたのかを引数に指定するのです。
この記号を、Action変数に格納するためです。
さあ、あとは、記号のボタンのコードだけです。
記号のボタンのイベントプロシージャを以下のように記述してみましょう。
Private Sub Plus_Click()
'足し算
'サブプロシージャの呼び出し
Calc Act.Plus
End Sub
Private Sub Minus_Click()
'引き算
'サブプロシージャの呼び出し
Calc Act.Minus
End Sub
Private Sub Multi_Click()
'掛け算
'サブプロシージャの呼び出し
Calc Act.Multi
End Sub
Private Sub Dev_Click()
'割り算
'サブプロシージャの呼び出し
Calc Act.Devi
End Sub
Private Sub btnEnter_Click()
'=の処理
'サブプロシージャの呼び出し
Calc Act.Equal
End Sub
画像も載せておきましょう。
いずれも、サブプロシージャを呼んでいるだけです。
その際、引数にその記号を指定していることに注意してください。
最後に、ACボタンのコードを書いておきましょう。
Private Sub btnAC_Click()
'ACボタンの処理
TextBox1.Text = 0
'初期化処理
InitCalc
End Sub
まさに、オールクリアですね。
それでは、実行してみてください。
いかがですか? 実際の電卓と同様の動作をするでしょう。
色々と試してみてください。
なかには、不思議な処理をする時があるかもしれません。
その理由を考えてみてください。
修正してみるのも勉強になります。
エクセルのバージョンは、2002(XP)以上でお願いします。
だい
自作の電卓・・・
時間に余裕が無いと向えませんね。
結構難題ですね。
身近にある電卓ですが、自作となると、結構大変でした。
僕らの周りには、英知の結晶がたくさんあるんですよね。