前のページ|次のページ

プログラミングの応用2


対話型プログラム

データの入出力をExcelのセルではなく,より一般的なプログラムのように,専用の窓を使用するようにできます.

メッセージボックス,インプットボックス

VBAにあらかじめ用意されている,表示用の「MsgBox関数」と入力用の「InputBox関数」を使用してみます.

MsgBox関数

MsgBox関数:選択したボタンに対応する「整数値」を返す.

ボタン VBAにおける表記
OK vbOK 1
キャンセル vbCancel 2
中止 vbAbort 3
再試行 vbRetry 4
無視 vbIgnore 5
はい vbYes 6
いいえ vbNo 7

構造

[ ] 内の引数は省略できます.

MsgBox(Prompt[, Buttons, Title, Helpfile, Context])
          
prompt
ダイアログボックスに表示する文字列
Buttons
ダイアログボックスに表示するボタンの数と種類,アイコンの種類
ボタンの種類と数
内容 VBAの表記
OK vbOKOnly
OK,キャンセル vbOKCancel
中止,再試行,無視 vbAbortRetryIgnore
はい,いいえ,キャンセル vbYesNoCancel
はい,いいえ vbYesNo
再試行,キャンセル vbRetryCancel
アイコン
内容 VBAの表記
警告 vbCritical
問い合わせ vbQuestion
注意 vbExclamation
情報 vbInformation
Title
タイトルバーに表示される文字列
Helpfile
ヘルプを表示する場合のヘルプファイルの指定
Context
ヘルプトピックに指定したコンテキスト番号

ImputBox関数

ImputBox関数:テキストボックスに入力されたデータを「文字列」として返す.

構造

[ ] 内の引数は省略できます.

InputBox(Prompt[, Title, Default, Xpos, Ypos, Helpfile, Context])
          
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
       
            

練習問題6-1

Excelのブックに新しいシートを追加し,VBEで新しい標準モジュールを挿入します.プロジェクトエクスプローラーに Sheet5 と Module5 が表示されるはずです.

Module5 のコードウィンドウに新しい Sub プロシージャ「ex_061」を作成します.

インプットボックスに正の整数を入力し,「偶数は2で割る,奇数は3倍して1を足す」という操作を繰り返すと結果は必ず1になることが予想されている(コラッツの予想)ので,1になるまでに掛かった操作の回数をメッセージボックスに表示するプログラムを作成する.

Sheet5にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_13に変えて下さい,ボタンはシートの左上あたりに配置してください.


ユーザーフォーム

予め用意されている基本的なコントロールを組み合わせて独自のフォームを作成し,プログラムで使用することができます.

ユーザーフォームの追加

VBE の「ツールバー」にある「ユーザーフォームの挿入」をクリックしてユーザーフォームを追加する.
vbe userform on

ユーザーフォームが追加されると,「プロジェクトエクスプローラー」に「UserForm1」が表示され,右の領域に「フォームデザイナー」が開き「UserForm1」が表示される.ここに「コントロール」と呼ばれる様々な入力に使用できる部品を設置して独自のフォームを作成する.使用するコントロールは,表示された「ツールボックス」から選択する.また,「プロパティウィンドウ」にはそのとき選択されているファームやコントロールのプロパティと現在設定されている「値」が表示される.
vbe userform start

コントロールの配置と設定

ツールボックスの使用したいコントロールをクリックし,続けて表示されている UserForm1 上の任意の場所をクリックするかドラッグすれば,コントロールが配置される.位置やサイズは選択状態でポイントをドラッグするか,プロパティウィンドウの値を入力すれば設定される.そのほかコントロールに対する様々な設定も,変更できるものはプロパティウィンドウで設定できる.
vbe userform control

イベントマクロの記述

実際のプログラムでのコントロールの使用は,コントロールをマウスでクリックするなど何らかの動作をした場合に発生する「イベント」と呼ばれる信号に対して,対応するプログラムを記述しておくことで実現する.このコントロールに対する操作に対応するプログラムを「イベントマクロ」と呼び,選択したコントロール上で「右クリック」→「コードの表示」によって UserForm1 に対するコードウィンドウが開くので,そこに使用したいコントロールのイベントに対して実行するプログラムを記述する.
vbe userform control code

フォームのコードウィンドウの上部には,左側にコントロール名,右にイベント名が表示される.ここを変更し,設定したいコントロールとイベントを選択してから下部のコードウィンドウに記述する.
vbe userform control code editor

プロシージャからの起動

標準モジュールにユーザーフォームを表示するためのプログラムを作成する.プロシージャの内容はユーザーフォームを呼び出すだけでよいので,次のようなステートメントを記述する(UserForm1 を表示する場合).

Show UserForm1
          

身長と体重を入力するフォームを作成し,「OK」するとBMIを計算して結果を表示するプログラムを作成する.

ユーザーフォームを挿入し,ユーザーフォームに必要なコントロールを追加する.今回は,文字を表示するための「ラベル」,操作するための「コマンドボタン」,入力するための「テキストボックス」を使用する.追加した後コントロールを選択すれば様々な設定を変更できる.基本的な設定は,選択したときに表示される対象となるコントロールの「プロパティウィンドウ」の各プロパティを記述する.
(「身長」,「cm」,「体重」,「kg」,「BMI:」がラベル.「計算」がコマンドボタン.「空白のボックス」がテキストボックス)
BMI UserForm

  1. ラベルに表示する文字を,プロパティウィンドウの「Caption」に設定する.
  2. コマンドボタンに表示する文字を,プロパティウィンドウの「Caption」に設定する.
  3. コマンドボタンをクリックしたときの動作をプログラムする.
    「右クリック」→ 「コードを表示」すると,ユーザフォームのコードウィンドウが表示されるので,イベントに対するプログラムを記述する.
    'ボタンをクリックした時のプログラム.このユーザーフォームでだけ有効にするために 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        
            
  4. 標準モジュールにユーザーフォームを呼び出すプロシージャを記述.シートのボタンにはこちらを登録する.
    Sub bmi_gui()
              UserForm1.Show
    End Sub
            

練習問題6-2

Module5 のコードウィンドウの ex_061 の下に新しい Sub プロシージャ「ex_062」を作成します.

「グー」,「チョキ」,「パー」の3つのボタンを作り,ボタンを押すとコンピューターとジャンケンをして「勝敗」を表示するユーザーフォームを使ったプログラムを作る.このとき,人間の出した手とコンピューターの出した手を表示すること.

ヒント:コンピューターはランダムに手を出すようにする.「Rnd()」という関数を使うと0~1の乱数を得られるので,次のように記述すると0,1,2がランダムに変数 pc に代入される.この数値を「グー,チョキ,パー」に対応させる.

Dim pc As Integer

pc = Int(3*Rnd())

              

Sheet5にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_14に変えて下さい,ボタンはシートの ex_13 の隣に配置してください.

オプション:通算の勝敗結果「何勝何敗何分」を表示し,人間の勝率を表示する.

オプションのヒント

  1. Form全体で有効な変数:UserFormのコードの最初,「Option Explicit」のすぐ後に変数を宣言
  2. 上記の変数の初期化:「開始ボタン」を作成し,そのコマンドとして実行させる.または,UserForm のコードに「UserForm_Initialize」というプロシージャを作成し,その中に記述する.

Excelの機能を使用してグラフを描く

関数のデータを自動的に作成して,Excelのグラフ作成機能を呼び出してグラフを描くプログラムを作ります.

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
                  

練習問題6-3

Module5 のコードウィンドウの ex_062 の下に新しい Sub プロシージャ「ex_063a または ex_063b」を作成します.

次のどちらかのプログラムを作成してください.

  1. ex_063a:次の関数の「散布図」グラフを描くプログラムを作成する.(\(\exp(x) = \mathrm{e}^x \)) \[ f(x) = \left( x^4 - 6x^2 - 3 \right)\exp\left(-\frac{x^2-1}{2}\right) \] 結果は新しいシートを追加して関数のデータを表示し,シートに埋め込まれたグラフにする.Sheet5にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_063aに変えて下さい,ボタンは ex_062x のボタンの隣に適当な間隔を開けて配置してください.
  2. ex_063b:次の関数の「3D等高線(ワイヤーフレーム)」グラフを描くプログラムを作成する.(\(\exp(x) = \mathrm{e}^x \)) \[ 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_063bに変えて下さい,ボタンは ex_062x のボタンの隣に適当な間隔を開けて配置してください.

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」を記述します.

練習問題6―4(オプション)

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]