データの入出力をExcelのセルではなく,より一般的なプログラムのように,専用の窓を使用するようにできます.
VBAにあらかじめ用意されている,表示用の「MsgBox関数」と入力用の「InputBox関数」を使用してみます.
MsgBox関数:選択したボタンに対応する「整数値」を返す.
| ボタン | VBAにおける表記 | 値 |
|---|---|---|
| OK | vbOK | 1 |
| キャンセル | vbCancel | 2 |
| 中止 | vbAbort | 3 |
| 再試行 | vbRetry | 4 |
| 無視 | vbIgnore | 5 |
| はい | vbYes | 6 |
| いいえ | vbNo | 7 |
[ ] 内の引数は省略できます.
MsgBox(Prompt[, Buttons, Title, Helpfile, Context])
| 内容 | VBAの表記 |
|---|---|
| OK | vbOKOnly |
| OK,キャンセル | vbOKCancel |
| 中止,再試行,無視 | vbAbortRetryIgnore |
| はい,いいえ,キャンセル | vbYesNoCancel |
| はい,いいえ | vbYesNo |
| 再試行,キャンセル | vbRetryCancel |
| 内容 | VBAの表記 |
|---|---|
| 警告 | vbCritical |
| 問い合わせ | vbQuestion |
| 注意 | vbExclamation |
| 情報 | vbInformation |
ImputBox関数:テキストボックスに入力されたデータを「文字列」として返す.
[ ] 内の引数は省略できます.
InputBox(Prompt[, Title, Default, Xpos, Ypos, Helpfile, Context])
インプットボックスに数値を入力し,偶数奇数を判定してメッセージボックスに表示するプログラムを作ります.メッセージボックスには「再試行」と「キャンセル」ボタンを作り,再試行が押されたときはもう一度インプットボックスを表示させ,キャンセルの時は終了させます.
Sub even_odd_gui()
Dim n As Integer
Dim msg_btn As Integer
Dim in_msg As String, out_msg As String
Dim in_titl As String, out_titl As String
in_msg = "正の整数を入力してください"
in_titl = "偶奇判定ー入力"
out_titl = "偶奇判定―出力"
n = Val(InputBox(Prompt:=in_msg, Title:=in_titl))
If n Mod 2 = 0 Then
out_msg = "偶数です"
Else
out_msg = "奇数です"
End If
If n ⁢> 0 Then
msg_btn = MsgBox(out_msg, vbRetryCancel + vbInformation, out_titl)
End If
If msg_btn = 4 Then
even_odd_gui
Else
Exit Sub
End If
End Sub
Excelのブックに新しいシートを追加し,VBEで新しい標準モジュールを挿入します.プロジェクトエクスプローラーに Sheet5 と Module5 が表示されるはずです.
Module5 のコードウィンドウに新しい Sub プロシージャ「ex_061」を作成します.
インプットボックスに正の整数を入力し,「偶数は2で割る,奇数は3倍して1を足す」という操作を繰り返すと結果は必ず1になることが予想されている(コラッツの予想)ので,1になるまでに掛かった操作の回数をメッセージボックスに表示するプログラムを作成する.
Sheet5にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_061に変えて下さい,ボタンはシートの左上あたりに配置してください.
予め用意されている基本的なコントロールを組み合わせて独自のフォームを作成し,プログラムで使用することができます.
VBE の「ツールバー」にある「ユーザーフォームの挿入」をクリックしてユーザーフォームを追加する.
ユーザーフォームが追加されると,「プロジェクトエクスプローラー」に「UserForm1」が表示され,右の領域に「フォームデザイナー」が開き「UserForm1」が表示される.ここに「コントロール」と呼ばれる様々な入力に使用できる部品を設置して独自のフォームを作成する.使用するコントロールは,表示された「ツールボックス」から選択する.また,「プロパティウィンドウ」にはそのとき選択されているファームやコントロールのプロパティと現在設定されている「値」が表示される.
ツールボックスの使用したいコントロールをクリックし,続けて表示されている UserForm1
上の任意の場所をクリックするかドラッグすれば,コントロールが配置される.位置やサイズは選択状態でポイントをドラッグするか,プロパティウィンドウの値を入力すれば設定される.そのほかコントロールに対する様々な設定も,変更できるものはプロパティウィンドウで設定できる.
実際のプログラムでのコントロールの使用は,コントロールをマウスでクリックするなど何らかの動作をした場合に発生する「イベント」と呼ばれる信号に対して,対応するプログラムを記述しておくことで実現する.このコントロールに対する操作に対応するプログラムを「イベントマクロ」と呼び,選択したコントロール上で「右クリック」→「コードの表示」によって
UserForm1 に対するコードウィンドウが開くので,そこに使用したいコントロールのイベントに対して実行するプログラムを記述する.
フォームのコードウィンドウの上部には,左側にコントロール名,右にイベント名が表示される.ここを変更し,設定したいコントロールとイベントを選択してから下部のコードウィンドウに記述する.
標準モジュールにユーザーフォームを表示するためのプログラムを作成する.プロシージャの内容はユーザーフォームを呼び出すだけでよいので,次のようなステートメントを記述する(UserForm1 を表示する場合).
Show UserForm1
身長と体重を入力するフォームを作成し,「OK」するとBMIを計算して結果を表示するプログラムを作成する.
ユーザーフォームを挿入し,ユーザーフォームに必要なコントロールを追加する.今回は,文字を表示するための「ラベル」,操作するための「コマンドボタン」,入力するための「テキストボックス」を使用する.追加した後コントロールを選択すれば様々な設定を変更できる.基本的な設定は,選択したときに表示される対象となるコントロールの「プロパティウィンドウ」の各プロパティを記述する.
(「身長」,「cm」,「体重」,「kg」,「BMI:」がラベル.「計算」がコマンドボタン.「空白のボックス」がテキストボックス)
'ボタンをクリックした時のプログラム.このユーザーフォームでだけ有効にするために Private をつける
Private Sub CommandButton1_Click()
'変数宣言
Dim shincho As Single
Dim taiju As Single
Dim bmi As Single
'テキストボックスの入力を変数に代入
shincho = TextBox1.Value
taiju = TextBox2.Value
'BMIの計算
bmi = taiju / (shincho / 100) ^ 2
'最後のラベルを書き換える & は文字列の接続を意味する
Label3.Caption = "BMI:" & bmi
End Sub
Sub bmi_gui()
UserForm1.Show
End Sub
Module5 のコードウィンドウの ex_061 の下に新しい Sub プロシージャ「ex_062」を作成します.
「グー」,「チョキ」,「パー」の3つのボタンを作り,ボタンを押すとコンピューターとジャンケンをして「勝敗」を表示するユーザーフォームを使ったプログラムを作る.このとき,人間の出した手とコンピューターの出した手を表示すること.
ヒント:コンピューターはランダムに手を出すようにする.「Rnd()」という関数を使うと0~1の乱数を得られるので,次のように記述すると0,1,2がランダムに変数 pc に代入される.この数値を「グー,チョキ,パー」に対応させる.
Dim pc As Integer
pc = Int(3*Rnd())
Sheet5にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_062に変えて下さい,ボタンはシートの ex_061 の隣に配置してください.
オプション:通算の勝敗結果「何勝何敗何分」を表示し,人間の勝率を表示する.
オプションのヒント
関数のデータを自動的に作成して,Excelのグラフ作成機能を呼び出してグラフを描くプログラムを作ります.
ワークシート上にあるデータを読み込んでグラフを表示するプログラムを作る.
新しいワークシートを作り,関数のデータを表示し,データをグラフ化するプログラムを作成する.
Sub func_plot()
'シートを表すオブジェクト型「Worksheet」の変数を宣言
Dim mySheet As Worksheet
'新しいシートを最後に追加し変数に代入し変数に代入(オブジェクト型の変数に代入するときは set を使う)
'シートの追加はシート全体を表すオブジェクト(注意:複数形)「Workseets」の「Add」メソッドを使用
'シートの数は「Count」プロパティで取得
set mySheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
'シートの名前を「関数1」に設定
mySheet.Name = "関数1"
'項目名を入力
mySheet.Cells(1,1).Value = "x"
mySheet.Cells(1,2).Value = "y"
'カウンター用の変数を宣言
Dim i As Integer
'データ用の配列変数を宣言
Dim x(100) As Double, y(100) As Double
'データ間隔を定数として設定
Const dx As Double = 0.1
'関数データ作成
For i = 0 To 100
x(i) = -5 + i*dx
y(i) = func1(x(i))
Next i
'各回の結果をセルに入力
For i = 0 To 100
mySheet.Cells(i+2,1).Value = x(i)
mySheet.Cells(i+2,2).Value = y(i)
Next i
'サブルーチンでグラフを描く
Call plot_xy(mySheet.Name)
End Sub
グラフにする関数はファンクションプロシージャで記述.今回は次の関数を使用. \[ f(x) = 10 \mathrm{e}^{-\frac{x^2}{5}} \sin(3x+1) \]
Function func1(x As Double) As Double
func1 = 10*Exp(-x^2/5)*Sin(3*x + 1)
End Function
作成された関数のデータを読み込み,散布図を表示するサブプロシージャ.
Sub plot_xy(s As String)
'変数の宣言
'シートに埋め込まれたグラフの領域1つを表すオブジェクト「ChartObject」型の変数を宣言
Dim myChartObject As ChartObject
'セルの範囲を表すオブジェクト「Renge」型の変数を宣言
Dim myRange As Range
'文字変数「s」として受け取った名前のシートに埋め込むグラフ領域を追加し変数に入力
'グラフシートの追加はグラフ領域全体を表すオブジェクト(注意:複数形)「ChartObjects」の「Add」メソッドを使用する
'Add の括弧内は埋め込む位置と領域の大きさ(領域の左上の左端からの水平位置,上端からの垂直位置,領域の幅,領域の高さ)
Set myChartObject = Worksheets(s).ChartObjects.Add(150, 50, 400, 300)
'シートで使用されているセル範囲「UsedRange」を変数に代入
Set myRange = Worksheets(s).UsedRange
'シートに埋め込まれたグラフ領域内のグラフそのものを表すオブジェクト「Chart」にプロパティを設定
With myChartObject.Chart
'グラフの種類を設定
.ChartType = xlXYScatterSmoothNoMarkers
'グラフのデータ範囲を設定
.SetSourceData myRange
'グラフ系列の方向を設定
.PlotBy = xlColumns
End With
End Sub
作成するグラフの種類は「ChartType」プロパティで選択できる.
| 名前 | 説明 |
|---|---|
| xl3DArea | 3-D 面 |
| xl3DAreaStacked | 3-D 積み上げ面 |
| xl3DAreaStacked100 | 100% 積み上げ面 |
| xl3DBarClustered | 3-D 集合横棒 |
| xl3DBarStacked | 3-D 積み上げ横棒 |
| xl3DBarStacked100 | 3-D 100% 積み上げ横棒 |
| xl3DColumn | 3-D 縦棒 |
| xl3DColumnClustered | 3-D 集合縦棒 |
| xl3DColumnStacked | 3-D 積み上げ縦棒 |
| xl3DColumnStacked100 | 3-D 100% 積み上げ縦棒 |
| xl3DLine | 3-D 折れ線 |
| xl3DPie | 3-D 円 |
| xl3DPieExploded | 分割 3-D 円 |
| xlArea | 分野 |
| xlAreaStacked | 積み上げ面 |
| xlAreaStacked100 | 100% 積み上げ面 |
| xlBarClustered | 集合横棒 |
| xlBarOfPie | 補助縦棒グラフ付き円 |
| xlBarStacked | 積み上げ横棒 |
| xlBarStacked100 | 100% 積み上げ横棒 |
| xlBubble | バブル |
| xlBubble3DEffect | 3-D 効果付きバブル |
| xlColumnClustered | 集合縦棒 |
| xlColumnStacked | 積み上げ縦棒 |
| xlColumnStacked100 | 100% 積み上げ縦棒 |
| xlConeBarClustered | 集合円錐型横棒 |
| xlConeBarStacked | 積み上げ円錐型横棒 |
| xlConeBarStacked100 | 100% 積み上げ円錐型横棒 |
| xlConeCol | 3-D 円錐型縦棒 |
| xlConeColClustered | 集合円錐型縦棒 |
| xlConeColStacked | 積み上げ円錐型縦棒 |
| xlConeColStacked100 | 100% 積み上げ円錐型縦棒 |
| xlCylinderBarClustered | 集合円柱型横棒 |
| xlCylinderBarStacked | 積み上げ円柱型横棒 |
| xlCylinderBarStacked100 | 100% 積み上げ円柱型横棒 |
| xlCylinderCol | 3-D 円柱型縦棒 |
| xlCylinderColClustered | 集合円錐型縦棒 |
| xlCylinderColStacked | 積み上げ円錐型縦棒 |
| xlCylinderColStacked100 | 100% 積み上げ円柱型縦棒 |
| xlDoughnut | ドーナツ |
| xlDoughnutExploded | 分割ドーナツ |
| xlLine | 折れ線 |
| xlLineMarkers | マーカー付き折れ線 |
| xlLineMarkersStacked | マーカー付き積み上げ折れ線 |
| xlLineMarkersStacked100 | マーカー付き 100% 積み上げ折れ線 |
| xlLineStacked | 積み上げ折れ線 |
| xlLineStacked100 | 100% 積み上げ折れ線 |
| xlPie | 円 |
| xlPieExploded | 分割円 |
| xlPieOfPie | 補助円グラフ付き円 |
| xlPyramidBarClustered | 集合ピラミッド型横棒 |
| xlPyramidBarStacked | 積み上げピラミッド型横棒 |
| xlPyramidBarStacked100 | 100% 積み上げピラミッド型横棒 |
| xlPyramidCol | 3-D ピラミッド型縦棒 |
| xlPyramidColClustered | 集合ピラミッド型縦棒 |
| xlPyramidColStacked | 積み上げピラミッド型縦棒 |
| xlPyramidColStacked100 | 100% 積み上げピラミッド型横棒 |
| xlRadar | レーダー |
| xlRadarFilled | 塗りつぶしレーダー |
| xlRadarMarkers | データ マーカー付きレーダー |
| xlRegionMap | マップ グラフ。 |
| xlStockHLC | 高値 - 安値 - 終値 |
| xlStockOHLC | 始値 - 高値 - 安値 - 終値 |
| xlStockVHLC | 出来高 - 高値 - 安値 - 終値 |
| xlStockVOHLC | 出来高 - 始値 - 高値 - 安値 - 終値 |
| xlSurface | 3-D 表面 |
| xlSurfaceTopView | 表面 (トップ ビュー) |
| xlSurfaceTopViewWireframe | 表面 (トップ ビュー - ワイヤーフレーム) |
| xlSurfaceWireframe | 3-D 表面 (ワイヤーフレーム) |
| xlXYScatter | 散布図 |
| xlXYScatterLines | 折れ線付き散布図 |
| xlXYScatterLinesNoMarkers | 折れ線付き散布図 (データ マーカーなし) |
| xlXYScatterSmooth | 平滑線付き散布図 |
| xlXYScatterSmoothNoMarkers | 平滑線付き散布図 (データ マーカーなし) |
Excelのシートからデータを読み込むこと無しに,プログラムの中だけでグラフを描くプログラムを作ることも可能.データは配列として用意する.
Sub func_plot2()
'カウンター変数を宣言
Dim i As Integer
'データを計算する間隔を定数として宣言
Const dx As Double = 0.1
'データを入力する配列を宣言
Dim x(100) As Double, y(100) As Double
'データを作成
For i = 0 To 100
x(i) = -5 + dx * i
y(i) = func2(x(i))
Next i
'グラフを描くサブルーチンを呼び出す
Call plot_xy2(x,y)
End Sub
今回は次の関数を使用する. \[ f(x) = 5 \cos^2(x) + 2 \sin(3x-2) \]
Function func2(x As Double) As Double
func2 = 5 * Cos(x) ^ 2 + 2 * Sin(3 * x - 2)
End Function
グラフを描くサブルーチン.今回はグラフを独立したシートとして表示する.
Sub plot_xy2(x() As Double, y() As Double)
'グラフを表すオブジェクト「Chart」型の変数を宣言
Dim myChart As Chart
'グラフシート全体を表すオブジェクト「Charts」のAddメソッドでグラフをシートとして最後に追加し,表示するグラフを変数に代入
Set myChart = Charts.Add(After:=Worksheets(Worksheets.Count))
'グラフのプロパティを設定
With myChart
'グラフシートに名前を設定
.Name = "関数2"
'グラフの種類を設定
.ChartType = xlXYScatterSmoothNoMarkers
End With
'グラフのデータ系列全体を表すオブジェクト「SeriesCollection」に新しい系列を「NewSeries」メソッドで追加
With myChart.SeriesCollection.NewSeries
'x軸のデータを配列で指定
.XValues = x
'値の項目名を設定
.Name = "f(x)"
'値のデータを配列で指定
.Values = y
End With
End Sub
Module5 のコードウィンドウの ex_062 の下に新しい Sub プロシージャ「ex_063a または ex_063b」を作成します.
次のどちらかのプログラムを作成してください.
3Dグラフを作成するときの函数データは,次のような構造のデータを作成してグラフ化します.
| y(0) | y(1) | y(2) | … | |
| x(0) | z(0,0) | z(0,1) | z(0,2) | |
| x(1) | z(1,0) | z(1,1) | z(1,2) | |
| x(2) | z(2,0) | z(2,1) | z(2,2) | |
| ︙ |
プロットするときの設定は,「SetSourceData」の後に「ChartType」を記述します.
Module5 のコードウィンドウの ex_063a または ex_063b の下に新しい Sub プロシージャ「ex_064」を作成します.
上記と同じ関数の「3D等高線(ワイヤーフレーム)」グラフを,関数のデータを表示せずに直接グラフを描き,グラフは独立したグラフシートに表示させるプログラムを作成する. \[ f(x,y) = \left((x^2+y^2)^2-6(x^2+y^2)-3\right)\exp\left(-\frac{x^2+y^2-1}{2}\right) \] Sheet5にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_064に変えて下さい,ボタンは ex_063x のボタンの隣に適当な間隔を開けて配置してください.
例題では,グラフ化するデータ系列 SeriesCollection を作成するときに, NewSeries メソッドを使用して系列を追加する方法を使用していますが,NewSeries メソッドは1度に1つの系列(1列分)しか追加できません.今回のように2変数のデータの場合は,\(y\)方向の全てのデータを追加する必要があります.
1回目の追加
.XValuew = x
.Name = y[0]
.Value = v(v:z[i,0]を1次元の配列に変換したもの)
| y[0] | |
| x[0] | z[0,0] |
| x[1] | z[1,0] |
2回目の追加
.XValuew = x
.Name = y[1]
.Value = v(v:z[i,1]を1次元の配列に変換したもの)
| y[0] | y[1] | |
| x[0] | z[0,0] | z[0,1] |
| x[1] | z[1,0] | z[1,1] |
3回目の追加
.XValuew = x
.Name = y[2]
.Value = v(v:z[i,2]を1次元の配列に変換したもの)
| y[0] | y[1] | y[2] | |
| x[0] | z[0,0] | z[0,1] | z[0,2] |
| x[1] | z[1,0] | z[1,1] | z[1,2] |