ゆんの業務改善ブログ

①生産性向上 ②業務改善 ③自動化 について情報発信しています。VBAプログラムは本当の初心者から他のアプリケーションを呼び出して使う上級者的な使い方まで幅広いレベルで解説していきます。

VBA |初心者向けオススメ独学本レビューまとめ

プログラミングを初めて学ぶ初心者がVBAを独学で身に付けるのに適した書籍を紹介します。レビューに関してはすべて私自身が実際に購入し、読んだ結果のものです。


目次

VBA |初心者向け独学本レビューまとめ

入門者~初心者向けの本

ストーリーで学ぶExcel VBAと業務改善のポイントがわかる本 Visual Basic for Applications

私が初めてVBAを勉強したときに利用した本です。一冊目にこの本に出会えたことはとてもラッキーだったと思います。プログラミング学習は、まず手を動かすことが大事だと言われます。しかし、本当の初心者だったら、どうやって手を動かしていいかすら分からないですよね。

その、「まず手を動かす」というはじめの一歩までたどり着くのに最適な入門書です。「非エンジニアのぱっとしないサラリーマンがVBAと出会い、業務改善に目覚める」と言うストーリーも共感を得やすく、とても読みやすいです。

この本のより詳しいレビューは VBA 初心者の1冊目にオススメ|ストーリーで学ぶ Excel VBAと業務改善のポイントがわかる本に書いています。

初心者~初級者向けの本

たった1秒で仕事が片づく Excel自動化の教科書

初期設定から、イベント処理までVBAで自動化プログラミングを行うのに必要な知識が一通り網羅された良著。上質紙に二色刷の本文で見やすく、解説も非常に分かりやすい。平均1ページあたり1つ以上のサンプルコード/画像で視覚的に分かりやすいため、この本が理解出来ずに挫折する事はないはず。

私が特に気に入ったのが第9章の全体像で描かれている文法のマインドマップです。VBAの基本的な文法の全体像を把握することができる為、ある程度進んだらこの第9章で自分がどこまで学習が進んできたのかを確認することで、立ち位置が分かり、より挫折しにくくなっていくでしょう。

入門者のExcel VBA

最終的に請求書を自動生成するプログラムを作成することを目指しながら、メッセージボックス、条件分岐、繰り返しと言った基本的な文法を解説していきます。売上データを請求書に変換するという具体的で実践的なテーマを事例にしているため、自分の日常業務への応用を思い描きながら読み進めることができます。

丁寧な説明で分かりやすく、初心者でも安心して読み進めることができます。読んで満足して終わりにならない様、本に出てきた文法を自分で手を動かして徹底的にアウトプットして使い込んでいくと着実に、確かなに実力を身に付けていくことができます。

初級者~中級者向けの本

脱入門者のExcel VBA 自力でプログラミングする極意を学ぶ

入門者のExcel VBAの続編です。この本の秀逸な点は、入門者と脱入門者の違いはどこにあるのかと言う事について冒頭で定義をし、その理由について明確に解説している点です。まず入門者と脱入門者の違いを認識する事ができ、具体的に何を身に着ければ脱入門者なのかがわかった状態で各章に取り掛かるため、それぞれの章において「この章をマスターすれば脱入門者なんだ」とモチベーションを保ちながら勉強を進めることができます。

デバッグのコツや処理の速さなど、単に自動化する先の実践的な技術に触れているのでこの本でレベルアップを図るのは有効です。

私の感覚では自分だけの便利ツールを作る事と他人のために自動化ツールを作ってあげるのには、頭一つ分レベルが違うと思っています。周囲より一歩上に行き、人に快適に安心して使ってもらえるツールを作れるようになる。そのような位置付けの一冊です。

VBAでSharePointにファイルをアップロードする

今回はVBAでSharepoint上にファイルをアップロードする方法を解説します。
目次

VBAでSharePointにファイルをアップロードする方法

Sharepoint(シェアポイント)とは

Sharepoint(シェアポイント)とはマイクロソフトが提供している情報共有アプリです。インターネットを閲覧するためのブラウザを利用します。インターネット上にドキュメントライブラリというようなデータを保存しておく場所があり、そこにデータをアップロードすることで、仲間とデータを共有することができます。

サンプルコード

サンプルコードは下記の通りです。

Sub SaveAtSharepoint()

    Dim url As String '保存先のシェアポイントのURL
    Dim conv_url As String 'シェアポイントのURLをフォルダ名に変換した文字列。フルパスなのでファイル名まで。
    Dim local_full_path As String 'シェアポイントに保存したいデータのフルパス
    Dim fso As Object 'FileSystemObjectのインスタンス化
    
    '>初期設定
    url = "シェアポイント上のURL" & "ファイル名.xlsx"
    local_full_path = "アップロードしたいファイルのフルパス"
    '<初期設定
    
    Set fso = CreateObject("Scripting.FileSystemObject")  'インスタンス生成
    conv_url = ConvertDirectoryPath(url)
    
    If fso.FileExists(local_full_path) Then
        fso.CopyFile local_full_path, conv_url
    End If
    
    Set fso = Nothing

End Sub

Function ConvertDirectoryPath(path) As String
    'このプロシジャはシェアポイントのURLをドキュメントライブラリのディレクトリパスに変換する
    ConvertDirectoryPath = Replace(path, " ", "%20")
    ConvertDirectoryPath = Replace(ConvertDirectoryPath, "/", "\")
    ConvertDirectoryPath = Replace(ConvertDirectoryPath, "http:", "")
End Function

内容の解説

内容について簡潔に解説します。そもそもシェアポイントにアップロードすると言っても、どこかに保存するだけです。その「どこか」を表すパスが分かれば、そこに保存したいファイルを保存するだけです。ファイルの操作にはFileSystemオブジェクトのCopyFileメソッドが使えます。

よって、ファイルの保存先が分かれば「シェアポイントにアップロード」できます。そして、シェアポイント上のファイルのURLに当たる部分をフォルダ名に置き換えるのがFunctionプロシジャの中身です。

<2019/12/27追記>
ご質問頂いたので追記します。url = "シェアポイント上のURL" & "ファイル名.xlsx"の「シェアポイント上のURL」の部分は、データをアップロードしたいところの、ドキュメントライブラリの名称までです。「DocLib1」のようなドキュメントライブラリっぽい名前のところまでを入力してみてください。

データをアップロードしたときのページのURLの最後に「Forms/AllItems.aspx」がついている場合はその直前の部分までだと思います。そのあたりにDocLib1のようなところがあると思うのでそのあとの「/」までを変数urlに入れるとうまくいくはずです。

「Forms/AllItems.aspx」がシェアポイントにおいて何を意味するかの説明はこのブログでは割愛します。

VBAでSharePointにアップロードする方法のまとめ

シェアポイントにファイルをアップロードする方法を簡単にまとめます。

  • シェアポイントにアップロードするとは、ある場所にデータを保存することである
  • シェポイントのURLから保存するフォルダのパスを求めることができる
  • FileSystemオブジェクトのCopyFileメソッドを使ってフォルダに保存する

一見難しそうな操作も分解してみると案外シンプルである事が分かります。なお、この記事を執筆するにあたり、下記URLの内容を参考にさせて頂きました。
VBA | Second Life of a Hungarian SharePoint Geek

<関連記事>

<ゆんの電子書籍>ゆんの電子書籍はすべてkindle unlimitedで読み放題です!

VBA ランダムな値を返すRnd関数の使い方

ランダムな小数の値を返すRnd関数を解説します。

目次

Rnd関数は0より大きく1よりランダムな小さい値を返す

まずはRnd関数を知るために、Rnd関数で生成した値を単に表示するためのサンプルを作成します。単にRndと書くと0より大きく1より小さいランダムな小数の値を返します。

Sub Rnd関数サンプル()

    MsgBox Rnd

End Sub

Rnd関数の結果をメッセージボックスで表示しただけ
実行結果

ランダムな小数の値が表示されました。Rndは関数なのでRnd()とかいてももちろんOK です。今回は引数を取らない場合の解説なので、()は省略できます。

Rnd関数の使い所

Rnd関数の便利な使い所を2点、紹介します。

  • ランダムな選択肢を生成する
  • サンプルデータ用のランダムな値を生成する

順に解説します。

ランダムな選択肢を生成する

Rnd関数は0より大きく、1より小さい小数の値を返します。そのため、戻り値に整数を掛け算して、小数点部分を切り捨てれば、0からその掛けた整数-1までのランダムな整数を発生させることができます。これを利用しておみくじプログラムを作成してみます。

Sub Rnd関数サンプル()

    Dim r As Long
    
    r = Int(Rnd * 4)
    
    Select Case r
        Case 0
            MsgBox "大凶"
        Case 1
            MsgBox "小吉"
        Case 2
            MsgBox "中吉"
        Case 3
            MsgBox "大吉"
    End Select
    
End Sub

これで実行するたびに、大凶、小吉、中吉、大吉のいずれかがメッセージボックスに表示されるプログラムができました。ぽいんとは、r= Int(Rnd * 4) の部分です。Intは小数部分を切り捨てて、整数にする関数です。4をかけ算してから小数部分を切り取ることにより、0~3までの4つの値のいずれかを生成しています。それをおみくじの出力に割り当てています。

サンプルデータ用のランダムな値を生成する

次に、サンプルデータ用の値を生成する方法です。このブログもサンプルデータがよく出てきますが、販売単価や商品コードと言った値は、このRnd関数で生成しています。

たとえば5桁の商品コードを生成したい場合は、桁数が変わらないように文字の「a」と0~9の数字 x 4桁を連結しています。

Sub Rnd関数サンプル2()

    Dim i As Long
    Dim r As Long
    Dim 商品コード As String
    
    商品コード = "a"
    For i = 1 To 4
        r = Int(Rnd * 10)
        商品コード = 商品コード & r
    Next i
    
    MsgBox 商品コード

End Sub

5桁の商品コードが生成できた
実行結果

Randomizeステートメントと併せて使う

これまで特に問題がないように使ってきましたが、実は問題があります。それは、Rnd関数は厳密にはランダムな値を返す関数ではない、と言うことです。Rnd関数が初めて実行されたとき、一度だけ、乱数表が生成されます。それを順番に読み取っているだけです。

よっておみくじアプリなら何度も繰り返していると、同じ結果が出力されることがばれてしまいます。この乱数表を新たに毎回生成することによって、本当にランダムな値を得ることができます。方法は簡単でRnd関数を使うたびにRandomizeステートメントを記述するだけです。

Sub Rnd関数サンプル_改善バージョン()

    Dim r As Long
    
    Randomize  '←ここに一行足しただけ
    r = Int(Rnd * 4)
    
    Select Case r
        Case 0
            MsgBox "大凶"
        Case 1
            MsgBox "小吉"
        Case 2
            MsgBox "中吉"
        Case 3
            MsgBox "大吉"
    End Select
    
End Sub

業務の自動化プログラムにRnd関数を使う事はないと思いますが、テスト用のデータを生成するときなど便利なので、ご活用下さい!

<お知らせ>
Excel VBAでクラスやオブジェクトの概念と使い方を丁寧に解説し、ワンランク上の実力を目指すガイドを書きました。この本で本物の実力を身に付けて一皮むけてみませんか?
books.rakuten.co.jp

VBA FileSystemObjectを使ってファイルやフォルダを操作する

VBAでファイルやフォルダを取り扱おうとすると、様々なメソッドを駆使する必要があり、なかなか大変です。今回はファイルやフォルダの取り扱いを一手に引き受けるコンピュータのファイルシステムを利用して、VBAで簡単にファイルやフォルダの取り扱いを行う方法を解説します。


目次

FileSystemObjectを使ってファイルやフォルダを操作する

早速、書き方について解説して行きます。

OLEを使う

他のプログラムの機能を借りてくるのがAPI、クラスを借りてくるのがOLEオートメーション(以下、OLE)です。今回はファイルシステムのクラスを借りてくるのでOLEです。OLEには事前バインディングと実行時バインディングの2つの方法があります。今回は実行時バインディングでサンプルコードを作成します。

サンプルコード

借りてくるクラス名を調べるためには、公式ドキュメントを参照します。公式ドキュメントによると、構文の所に、Scripting.FileSystemObject、と書いてありその下に、メソッドが色々と解説されています。それに従ってインスタンスの生成とメソッドを利用すればOKです。

Sub SampleFolderというフォルダを作成するサンプル()

    Dim fso As Object 'インスタンスを生成するための適当な変数を用意する
    
    Set fso = CreateObject("Scripting.FileSystemObject") 'インスタンスの生成
    fso.CreateFolder ("C:\SampleFolder") ’インスタンスを利用

End Sub

無事にCドライブ直下にSampleFolderというフォルダを作成することができました。せっかくなので別のメソッドも試してみます。前項のプログラムにフルパスを生成するBuildPathメソッドを加えて新たなフルパスを取得しました。そのフルパスを使って新たなエクセルファイルを保存します。

Sub フォルダ生成しその中にファイルを保存するサンプル()

    Dim fso As Object
    Dim fullpath As String
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    fso.CreateFolder ("C:\SampleFolder")
    fullpath = fso.BuildPath("C:\SampleFolder", "samplefile.xlsx")
    
    Workbooks.Add
    ActiveWorkbook.SaveAs Filename:=fullpath
    
End Sub

プログラム自体は難しくありませんね。OLEは公式ドキュメントにたどり着けるかどうかが鍵です。

FileSystemObjectのBuildPathメソッドを利用した
新しく作成したフォルダの中に新しいエクセルファイルを追加した

今回のファイルシステムのクラス、ブラウザのクラス、Outlookのクラスの3つは3大よく使うOLEだと思いますので、これらの公式ドキュメントだけでも押さえておくと、いちいち調べなくて良いかも知れません。あるいは、よく使う部分は使い回せるように、インスタンスの生成までは共通のコードとして保存しておくと良いと思います*1

FileSystemObjectの使い方 まとめ

以上、FileSystemObjectの使い方でした。ポイントとしては下記の通りです。

  • VBAでファイルやフォルダを操作するのは結構大変なので、FileSystemObjectが便利
  • OLEは公式ドキュメントまでたどり着けさえすれば大丈夫
  • よく使うOLEはインスタンスを生成するところまでひとかたまりのコードとして保存しておく

<関連記事>

<ゆんの電子書籍>
ゆんの電子書籍はすべてkindle unlimitedで読み放題です!

*1:あとで使い回せるように部分的に汎用的に記述したひとかたまりのプログラムのことをスニペットと言います

VBA Do ~ Loopで繰り返しを自在に操る

今回はVBAでDo Loopを使って繰り返しをする方法を解説します。この記事はFor ~ Nextの繰り返しは使ったことがあるものの、Do ~Loopには馴染みが薄いという方を読者に想定しています。

目次

Do ~ Loop を自在に使いこなす

VBAのDo ~ Loopステートメントは自由度の高い繰り返しが可能な制御構文です。さっそく使い方について見ていきましょう。

Do ~ Loopの文法

キホンの4通り

結論から入ります。とりあえずこの4つ、しかも特に上の2つだけ知っておけばOKです。

  • Do While ~ Loop型
Sub DoLoopの繰り返し1()
    
    Dim n As Long
    
    Do While n < 10
        'ここに繰り返す処理
        Debug.Print n '結果:0~9まで表示される
        n = n + 1
    Loop
    
End Sub

まず、条件式のWhileがDoの横に来ているパターンです。While以下の条件が成り立つ間、Do ~ Loopの中身が繰り返されます。ポイントは、条件の中身が判定されてからDo ~ Loopの中身が繰り返されるところです。そのため、今回の例ではn = 10の時は繰り返しの中身が実行されず10がイミディエイトウィンドウに表示されません。

  • Do Until ~ Loop型

次にWhileのところにUntilキーワードを使う場合を見ていきます。上の例と下の例2つだけマスターすればとりあえず、OKです。

Sub DoLoopの繰り返し2()
    
    Dim n As Long
    
    Do Until n >= 10
        'ここに繰り返す処理
        Debug.Print n
        n = n + 1
    Loop
    
End Sub

Untilは「~まで」という意味です。条件を満たさない状態からループが始まり、Until以降の条件を満たすようになるとループを修了します。こちらも条件の中身が判定されたからDo ~ Loopの中身が実行されるかどうかが決まります。

  • Do ~ Loop While型

条件式はLoopの横に書くこともできます。

Sub DoLoopの繰り返し3()
    
    Dim n As Long
    
    Do
        'ここに繰り返す処理
        Debug.Print n
        n = n + 1
    Loop While n < 10
    
End Sub

F8で一行ずつ実行してみるとよくわかりますが、とりあえずDo ~ Loopの中身を実施して、その後、条件式の判定が行われています。今回の例では実行結果は変わりません。しかし、カウントアップする値をセルの行番号にしているときなど、条件式を前にするか後にするかによって、中身が実行されるかどうかが変わる場合があります。

  • Do ~ Loop Until型

条件式をLoopの横に着けるパターンのUntil型です。

Sub DoLoopの繰り返し4()
    
    Dim n As Long
    
    Do
        'ここに繰り返す処理
        Debug.Print n
        n = n + 1
    Loop Until n >= 10
    
End Sub
これがDo ~ Loopの魅力、WhileもUntilも書かない

以上で基本的なDo ~ Loopの使い方は網羅したのですが、条件式を書かないことも可能です。そしてこれこそが、Do ~ Loopのメリットです。

Sub DoLoopの繰り返し5()

    Dim n As Long
    
    Do
        'ここに繰り返す処理
        Debug.Print n
        n = n + 1
        
        If n >= 10 Then
            Exit Do
        End If
        
    Loop

End Sub

Doの横にも、Loopの横にも条件式がありません。その代わり、Do ~ Loopの中にIf文でループを抜ける時の条件を記述して、Exit Doでループを抜けています。If文でループを抜ける条件を記述することができるので、複雑な条件を設定することができます。

For ~ Nextより自由度の高いDo ~ Loop

おなじ繰り返しの制御構文に、For ~ Nextステートメントがあります。こちらはカウント用の変数が一度決めた値になるまで繰り返すという制御構文です。カウントの幅はStepキーワードを使って変更することができますが、ある値になるまで繰り返す、というように、繰り返しの条件の設定の仕方自体に縛りがあります。

一方 Do ~ Loopステートメントはあらかじめループを終える条件をDoのあとやLoopの後の条件式の部分に設定しなくても、Exit Doステートメントを使って自由なタイミングでループを抜けることができます。まさに自在にループを抜けるタイミングを設定することができるため、複雑な処理をしたい時にとても便利です。

例えば、ワークシートの操作で不要な行を削除する、といったような時にはFor ~ Nextでループするよりも、Do ~ Loopで繰り返すほうがやりやすいでしょう。行を削除すると行番号がずれるからです*1

Do ~ Loopの使い方 まとめ

  • Do ~ Loopには基本の4通りの書き方がある
  • WhileもLoopも書かずに、実行内容の中にIf文でループを抜ける条件を設定すると細かい処理が可能となる
  • For ~ Nextでは記述しにくい処理もDo ~ Loopでは簡単に書ける場合がある

Do ~ Loopをマスターしてより自由度の高い繰り返しを実装していきましょう!

<お知らせ>
Excel VBAでクラスやオブジェクトの概念と使い方を丁寧に解説し、ワンランク上の実力を目指すガイドが電子書籍になりました。この本で本物の実力を身に付けて一皮むけてみませんか?
books.rakuten.co.jp

*1:不要な行の削除ではなく、必要な行を別シートに転記の方が望ましい場合が多いように思います。しかし、Do ~ Loopの使い勝手の良さを理解してもらう為に、不要な行を削除することを例として取り上げまし

VBA MkDir|今月のフォルダを作成する

フォルダを作成するMkDirステートメントの使い方を解説します。サンプルコードでは、毎月月初に当月のフォルダを作成するコードを取り上げます。

目次

今月のフォルダを作成する

いきなり文法の結論

ずばり、こう書きます。

MkDir パス

Cドライブ直下に「サンプルフォルダ」というフォルダを作るサンプルコードは下記の通りです。

Sub C直下にフォルダを作る()

    MkDir "C:\サンプルフォルダ"
    
End Sub

MkDir の後に作成したいフォルダのフルパスを書きます「\」は「¥」という理解でOKです。環境によって見え方が違うだけでバックスラッシュと円マークは同じ意味です。

エラーになるケースを補足説明

文法*1はシンプルで簡単です。エラーになる場合について抑えておきましょう。エラーになるパターンは2つだけです。

  • すでに存在しているフォルダのパスを指定する
  • 親フォルダが存在していない

1点目については先ほどのサンプルコードをもう一度実行してみれば確認できます。一度目はエラーになりませんが、二度目はエラーになります。すでにCドライブに「サンプルフォルダ」というフォルダが存在するからです。

パス名は無効ですのエラーが表示された
同じフォルダを二度作ろうとするとエラーになる

2点目については、上のサンプルコードで作成したサンプルフォルダの中に、「今月のフォルダ」を作成することを考えます。

Sub サンプルフォルダの中に今月のフォルダを作る()

    MkDir "C:\サンプルフォルダ\今月のフォルダ"
    
End Sub

実行してみると確かに「サンプルフォルダ」の中に「今月のフォルダ」が作成されていました。

無事に「サンプルフォルダ」の中に「今月のフォルダ」が作成された
実行結果

今回うまくいったのは、すでにサンプルフォルダを作成済みだったからです。サンプルフォルダを一度消して、このプロシジャを実行してください。すると、今度は別のエラーが出ます。

存在しない親フォルダの中にフォルダを作成することはできない
「パス名が無効です」のエラーが出た。

今回は「パス名が無効です」というエラーが出ました。存在しない「サンプルフォルダ」の中に「今月のフォルダ」を作成する命令を記述したため、「そんな親フォルダありません」というエラーになった、というわけです。これらを言い換えると、一番最後のパスのところだけ、まだ存在しないフォルダ名にして、親の部分はすべて既存のフォルダである必要がある、ということです。

今回やりたいことのイメージ

先ほど作成したサンプルフォルダに6桁の数字でYYYYMMという名前のフォルダを作成することが今回やりたいことです。

今回やりたいイメージは6桁の数字でフォルダ名をつけることだ
再掲:「今月のフォルダ」という名前ではなく201912のような名前を付けたい

月ごとに何かのデータをYYYYMMというフォルダに日々ためていく業務を想像してください。月初に一回だけ、今月のフォルダを作りたい。という感じです。

サンプルコード

Sub 当月のYYYYMMフォルダを作る()
    
    Dim 当月num As Long
    
    当月num = Year(Date) & Format(Date, "MM")
    MkDir "C:\サンプルフォルダ\" & 当月num
    
End Sub

無事に当月のフォルダを生成できた
実行結果

まとめ ~MkDirをつかって今月のフォルダを作成する方法~

  • 文法は単純で、MkDir パス名
  • エラーになる2つのパターンだけ覚えよう

<関連記事>

<お知らせ>
Excel VBAでクラスやオブジェクトの概念と使い方を丁寧に解説し、ワンランク上の実力を目指すガイドが電子書籍になりました。この本で本物の実力を身に付けて一皮むけてみませんか?
books.rakuten.co.jp

*1:プログラムの文法の事をシンタックスと言います

VBA 高速化 | ループ検索の速度を上げる方法(バイナリーサーチ)

今回はVBAでループを使った検索を高速化する方法を解説します。この記事はApplication.ScreenUpdating = Falseや配列を使ってセルの書き込み回数を減らしてもなお、For文を使ったループ検索の部分で満足できる高速化が実現できていない人を読者に想定しています。

目次

For ~ Nextステートメントによるループ検索を高速化する

この解説記事の説明の流れ(前提⇒サンプルデータの説明⇒サンプルを使った実装)

この記事では、高速化の前提を簡単に説明した後、「販売実績」の商品コードに「商品マスタ」の販売単価の情報を反映させるサンプルを使って、高速化の方法を解説します。

バイナリーサーチという検索アルゴリズムを使って高速化を行います。

高速化を試みる前に知っておきたい前提(小手先の対策と本質的な対策)

高速化の本質は余計なことはしない事です。理由はPCのスペックをプログラミングで向上させることはできないからです。処理を高速化するには余計な処理を省いて最小限のことを実行する事です。

そして余計なことを省く方法には大きく分けて2つのタイプがあります。

  • 小手先の高速化
  • 本質的な高速化

小手先の高速化は、Application.ScreenUpdating = False のようにいつでも簡単に使える有効な高速化の方法です。一方、本質的な高速化は場面に応じて最適な処理をプログラムで組むことです。どちらがいい、と言うわけではありません。どちらも効果はあります。しかし、小手先の高速化では限界があります。小手先の高速化の施策だけでは満足が得られず、それ以上の無駄を省く必要がある場合に本質的な高速化を目指しましょう。

本題~今回用意したサンプル~

解説のためのサンプルは「商品マスタ」と「販売実績」の2つです。いずれも大量のデータが存在します。

サンプル1ー商品マスタ

商品マスタは10437行存在します。商品コードと販売単価の2列のデータです。商品コードは「a」から始まり、0~9の数値が6桁が続く、合計7桁で構成された文字列です。商品コードに重複はありません。

販売単価は最大で4桁、最小で2桁の数値です。日本円をイメージしています。販売単価の重複はあります。

「商品マスタ」には1万行以上の商品データが存在する
今回取り扱うサンプルデータの「商品マスタ」。ヘッダ行を含め、10437行ある

サンプル2ー販売実績ー

一方、販売実績は商品コードと販売数量が記録されています。売上高を集計するためにB列に一列手作業で挿入して、販売単価を反映させようという意図です。後工程としてはB列とC列の値をかけ算する予定です。

販売実績データはPOS*1から商品コードと販売実績数量を抜き出したデータを想定しています。

販売実績データはB列が空白でC列に販売数量が記載されている。
サンプル2の販売実績データ。全部で20万行ある。

以上がサンプルデータです。やりたいことはシンプル。販売実績シートに販売単価を反映させるだけです。ただ、データ量が多いだけ。

実装

それでは実装していきます。

単なるVLOOKUP

まずは単にVLOOKUPを当てた場合です。

Sub 単なるVLOOKUP()
    
    Dim t1 As Date
    Dim t2 As Date
    
    Dim マスタデータの最終行 As Long '最終行取得用
    Dim 販売実績データの最終行 As Long '最終行取得用
    Dim 検索範囲 As Range
    Const データの初めの行 As Long = 2
    
    Dim i As Long '行方向のカウントUP用
    
    マスタデータの最終行 = Sheets("商品マスタ").Cells(Rows.Count, 1).End(xlUp).row
    Set 検索範囲 = Sheets("商品マスタ").Range(Cells(1, 1), Cells(マスタデータの最終行, 2))
    販売実績データの最終行 = Sheets("販売実績").Cells(Rows.Count, 1).End(xlUp).row

    t1 = Now 'ここからが本番
    
    With Sheets("販売実績")
        For i = データの初めの行 To 販売実績データの最終行
            .Cells(i, 2) = Application.WorksheetFunction.VLookup(.Cells(i, 1), 検索範囲, 2, False)
        Next i
    End With
    
    t2 = Now 'ここまでが本番

    Debug.Print t2 '終了時刻
    Debug.Print t1 '開始時刻
    
End Sub

実行に掛かった時間は47秒でした。

バイナリーサーチで高速化する

次に本格的に高速化を狙います。バイナリーサーチはデータを昇順に並び替え、データの真ん中のところで区切ります。真ん中の所の値が探している値より小さければ探している値は大きい方の半分にあるはずです。逆に真ん中の値が探している値より大きければ、小さい方の半分にあるはずです。

こうして半分に分けてどちらにあるかを繰り返していけば、いつか検索している値にたどり着く、と言うわけです。ミソは、逐次探していないところです。

文字列も不等号の演算子で大小の判定ができる事を利用します。

Sub バイナリーサーチで検索する()

 '下準備
    Dim t1 As Date
    Dim t2 As Date
    
    Dim マスタデータの最終行 As Long '最終行取得用
    Dim 販売実績データの最終行 As Long '最終行取得用
    Const データの初めの行 As Long = 2
    
    Dim i As Long '行方向のカウントUP用
    
    マスタデータの最終行 = Sheets("商品マスタ").Cells(Rows.Count, 1).End(xlUp).row
    販売実績データの最終行 = Sheets("販売実績").Cells(Rows.Count, 1).End(xlUp).row

    t1 = Now 'ここからが本番
    Application.ScreenUpdating = False
    
    '>商品マスタのデータを「商品コード」をキーに昇順に並び替える
    Dim 商品マスタarr As Variant
    
    Sheets("商品マスタ").Activate
    
    Range(Cells(1, 1), Cells(マスタデータの最終行, 2)).Sort _
        Key1:=Cells(1, 1), _
        Order1:=xlAscending, _
        Header:=xlYes
        
    商品マスタarr = Range(Cells(1, 1), Cells(マスタデータの最終行, 2))
        
        
    '>販売実績のシートで上から一品目ずつバイナリーサーチで検索する
    Dim 検索したい商品コード As String '販売実績データの商品コードを入れる
    DimAs Long 'データの検索範囲の下限の行番号
    DimAs Long ' データの検索範囲の上限の行番号
    Dim 中央 As Long 'データの検索範囲の真ん中の行番号
    
    Sheets("販売実績").Activate
    
    For i = データの初めの行 To 販売実績データの最終行
    '販売実績の最初から最後まで繰り返す
        
        '>>商品コードごとに初期設定
        検索したい商品コード = Cells(i, 1)= データの初めの行
        高 = マスタデータの最終行
        
        'ここからがバイナリーサーチの部分
        Do While<= '下限の行と上限の行番号が一致するまでの間繰り返す

            中央 = Int((+) / 2)  '2で割り切れなかったら切り捨て
            If 商品マスタarr(中央, 1) = 検索したい商品コード Then
                Cells(i, 2) = 商品マスタarr(中央, 2) ',見つかったら販売単価を返す
                Exit Do
            ElseIf 商品マスタarr(中央, 1) > 検索したい商品コード Then= 中央 - 1
            Else= 中央 + 1
            End If
        Loop
        'バイナリーサーチここまで
        
    Next i
    
    Application.ScreenUpdating = False
    t2 = Now 'ここまでが本番

    Debug.Print t2 '終了時刻
    Debug.Print t1 '開始時刻

End Sub

実行時間は9秒でした。単なるVLOOKUPの約5分の1の時間で終了することができました。

すべてSubプロシジに記述しましたが、サンプルコード内のコメントの「ここからがバイナリーサーチの部分」~「バイナリーサーチここまで」の部分をFunctionプロシジャにして分離するととてもすっきりとします。

「ここからがバイナリーサーチの部分」より前の部分は、商品マスターのデータの順番を昇順に並び替えたり配列に格納したりといった準備が長くなっています。

しかしバイナリーサーチのコードそのものは案外すっきりしていますね。

セルに値を書き込むところに時間が掛かっているので、配列の中で計算して最後にペタッとシートに戻せばさらなる高速化を図る事ができます。

高速化の本質は余計なことをしない、の感触が掴めたでしょうか。

小手先の高速化と本質的な高速化を併用して、ユーザーフレンドリーなツールに仕上げていきましょう!

<関連記事>

*1:販売時点データ。レジでバーコードを「ピッ」っとしたら商品コードと数量が販売実績データに蓄積される仕組み

VBA コンボボックスでユーザーに直接入力させない|ユーザーフォームの使い方

VBAのユーザーフォームで使えるコントロールのひとつ、コンボボックスの使い方を解説します。この記事は非エンジニアの会社員でVBAで自動化ツールを開発している人を読者に想定しています。

目次

コンボボックスの使い方

まずはコンボボックスとは何かを見て行きましょう

コンボボックスとは

コンボボックスとは、プルダウンリストのように選択肢の中からユーザーに値を選択してもらうためのコントロールです。プルダウンリストとの違いは、ユーザーが直接入力する事ができる点です。そのため、ユーザーに選択肢に存在していない値を入力されたくない場合は、プログラム側でそれを防ぐ工夫が必要です。

この記事のサンプルでは、売上集計作業で売上高を求める作業を想定します。ユーザーにコンボボックスから売上集計をする販売地域を選択してもらうイメージです。営業所が存在しない地域を選択して欲しくない、と言う前提で、コンボボックスへの直接入力を防止する方法も解説します。

コンボボックスを実装する

早速コンボボックスを実装します。ツールボックスからコンボボックスを選択してユーザーフォーム上に設置します。ツールボックスが表示されていない場合は表示、ツールボックスで表示させる事ができます。

プルダウンリストのような見た目のコントロールがコンボボックス
コンボボックスを選択する

ついでに実行ボタンを設置しておきます。


コンボボックスと実行ボタンを実装したところ
コンボボックスと実行ボタンを実装したところ

いつものように分かりやすいオブジェクト名に変更できます。表示⇒プロパティウィンドウでプロパティウィンドウを表示し、オブジェクト名を変更します。サンプルでは下記の様にオブジェクト名を設定しました。

  • コンボボックス ⇒ 販売地域cbx
  • 実行ボタン ⇒ 実行btn

これでユーザーフォームの設計が完了しました。

フォームモジュールにイベントプロシジャ記述する

◆ Initializeイベントで選択肢を作成する
設計が完了したので、フォームモジュールにイベントプロシジャを記述します。

エディタのプルダウンリストからUserFormのInitializeイベントプロシジャを選択します。

プルダウンリストからUserFormのInitializeイベントを選択する
Initializeイベントのプロシジャを挿入する

InitializeイベントはUserFormが表示されたときにまず実行されるイベントです。Initializeイベントを利用してコンボボックスに選択肢を作成します。

’これはフォームモジュールに記述します

Private Sub UserForm_Initialize()

    販売地域cbx.AddItem "札幌"
    販売地域cbx.AddItem "東京"
    販売地域cbx.AddItem "名古屋"
    販売地域cbx.AddItem "大阪"
    販売地域cbx.AddItem "福岡"
    
End Sub

コンボボックスのAddItemメソッドは引数の文字列をコンボボックスの選択肢に追加します。今回は全ての選択肢をベタ打ちしていますが、選択肢が多い場合はどこかのワークシートに選択肢の一覧表をつくっておいて、For~Next文のループで選択肢を作るのが良いでしょう。

コンボボックスの下向き三角を押したところ
無事にコンボボックスが実装できた

コンボボックスの右端の下向き三角を押すと選択肢が表示されました。コンボボックスの完成です。

ユーザーによるコンボボックスへの選択肢以外の直接入力を認めない

冒頭で説明した通り、コンボボックスはユーザーが直接自由に記入することが可能です。存在しない販売地域を手で入力されると、その後のプロシジャでエラーが出ることが考えられるため、選択肢以外の入力を認めない様にしておきましょう。

コンボボックスの値が入力された瞬間に選択肢以外の文字が入力されたら修正を促すイベントプロシジャを挿入します。

Changeイベントはコンボボックスの値が変更された事がトリガーのイベント
Changeイベントを選択する

ComboBoxのChangeイベントはコンボボックスの値が変更された事がトリガーのイベントです。

Private Sub 販売地域cbx_Change()
    
    If 販売地域cbx.Value <> "札幌" And _
       販売地域cbx.Value <> "東京" And _
       販売地域cbx.Value <> "名古屋" And _
       販売地域cbx.Value <> "大阪" And _
       販売地域cbx.Value <> "福岡" And _
       販売地域cbx.Value <> "" Then '・・・A
       
            MsgBox "入力値が誤っています。"

            販売地域cbx.Value = ""  '・・・B
            販売地域cbx.SetFocus '・・・C
           
    End If
    
End Sub

プログラムのA~Cの部分についてそれぞれ解説します。

  • A:If~End Ifステートメントの条件

選択肢以外の値を認めないための条件を記述します。選択肢のいずれの文字列とも一致しない場合に実行するようにしています。ポイントは空白を許していないことです。

今回は、コンボボックスの選択肢以外の文字が入力された時に、選択肢からの入力を促すと共に、誤入力の文字をクリアします。ユーザーが再入力しやすいようにです。ComboBoxのChangeプロシジャはComboBoxのValueプロパティ(=表示されている値)が変更になったことをトリガーとしているため、誤入力の文字をクリアした瞬間に再びChangeプロシジャが実行され、2度「入力値が誤っています。」とメッセージが表示されてしまいます。それを防ぐ為に、空白への変更時には実行しないようにしています。

  • B:販売地域cbx.Value = ""

ユーザーが再度入力しやすいように空白に戻しています。選択肢からマウスでクリックする事を想定しているので、必須ではありません。

  • C:販売地域cbx.SetFocus '

ユーザーが再度入力しやすいようにコンボボックスを選択した状態にしています。こちらもBと同じで、必須ではありません。


あとは、実行ボタンが表示された時のプロシジャを記述すればユーザーフォームの完成です。

Private Sub 実行btn_Click()

    MsgBox 販売地域cbx.Value & "が選択されました"
    
End Sub

ユーザーフォームを表示させるプロシジャも標準モジュールに作成しておきましょう。

コンボボックスから選択肢を選択して実行ボタンを押したところ
実行結果

コンボボックスの使い方まとめ

  • コンボボックスは選択肢から選択してもらうことを想定したコントロールである
  • ユーザーが直接入力する事もできる
  • 選択肢はInitializeイベントでユーザーフォームが表示された時などに生成する方法がある*1
  • 直接入力を許さないための記述はプログラムの中に記述する

コントロールを上手に使ってユーザーに優しいユーザーインターフェースを目指しましょう。

<関連記事>

*1:ユーザーの操作に応じて選択肢が変わるような場合も考えられます。例:ひとつ目のコンボボックスから「関西」を選択すると、2つめのコンボボックスの選択肢は大阪と京都になる、など

VBA チェックボックスをFor文でループして検知する|ユーザーフォームの使い方

VBAのユーザーフォームでチェックボックスを使う方法について解説します。この記事は非エンジニアの会社員でVBAのツールでユーザーフォームの使い方を調べている方を読者に想定しています。

目次

チェックボックスを使う

まずチェックボックスとは何かについて確認します。

チェックボックスとは

チェックボックスは選択肢の中からユーザーにひとつ、もしくは複数の選択させるためのコントロールです。オプションボタンとの違いは複数選択が可能なことです。

チェックボックスを実装する

実際にチェックボックスを実装します。ツールボックスからチェックボックスを選択して、ユーザーフォームにチェックボックスを設置します。決定ボタンも設置しておきます。

ユーザーフォームにチェックボックスと決定ボタンが設定されている。
今回設計したチェックボックスと決定ボタンが設置されたユーザーフォーム

コントロールのオブジェクト名は分かりやすい様に下記の様に設定しました。

  • 札幌cb
  • 東京cb
  • 大阪cb
  • 福岡cb
  • 決定btm
フォームモジュールにイベントプロシジャを記述する

イベントプロシジャを作成します。実装する内容としては、決定ボタンが押されたときに、チェックボックスにチェックが入っている地域の名前をメッセージボックスに表示します。今回はチェックボックスが4つしかないため、一つ一つIf文で記述する事もできます。しかし、チェックボックスが10個など多数にわたるときのことを考慮して、For文でループしてそれぞれのチェックボックスの値を調べル方法で実装します。

Private Sub 決定btn_Click()
    
    Dim ctrl As Control '・・・A
    
    For Each ctrl In Controls '・・・B
        If InStr(ctrl.Name, "cb") <> 0 Then '・・・C
            If ctrl.Value = True Then '・・・D
                Debug.Print ctrl.Caption '・・・E
            End If
        End If
    Next ctrl
    
    Unload Me ’・・・F
    
End Sub

For文でループしてユーザーフォーム上に設置された全てのコントロールをループします。For Each~Nextステートメントでブック内の全てのシートをループで検索するのと同じイメージです。プログラム内にコメントアウトしたA~Fそれぞれの部分について解説します。

  • Aの部分

今回はコントロールを一つ一つループで確認するので、コントロールを一時的に格納する変数を宣言します。コントロールの略でcntrlとしました。

  • Bの部分

ひとつ一つのコントロールをループするFor Each~Nextステートメントです。このユーザーフォーム内の全てのコントロールをループします。

  • Cの部分

すべてのコントロールをループするため、余計なコントロールをチェックしなくて良い様にします。今回はこのIf文は不要です。理由はValueプロパティにTrueを持つコントロールがチェックボックスしかないためです。しかし、オプションボタンなど他にTrueを持ち得るコントロールがある場合は、ループでチェックする対象のみチェックするために分岐が必要です。

今回は全てのチェックボックスのオブジェクト名に「cb」という文字をつけたので cbと言う文字を含むかどうかで分岐を行いました。

  • Dの部分

チェックボックスはチェックが入っていればTrue 、チェックが入っていなければFalseを返します。よってチェックボックスのValueプロパティがTrueの場合に抽出する分岐を記述しました。

  • Eの部分

Debug.PrintはイミディエイトウィンドウにDebug.Print 以降に記述した内容を表示します。ctrl.Caption、つまりチェックボックスに表示されている文字列を表示させるようにしました。イミディエイトウィンドウはデバッグの時に役立つので、この際表示させておきましょう。表示⇒イミディエイトウィンドウで表示させる事ができます。

  • Fの部分

プログラムが最後まで実行されても、ユーザーフォームが開いている限りマクロは実行中の状態のままとなります。全ての命令が終わったらユーザーフォームを閉じるようにしています。

ここまで来たら、標準モジュールにUserForm1.Showを実行するSubプロシジャを記述して実際に実行してみます。

決定ボタンを押す直前の画面
札幌と大阪のチェックボックスを選択した

選択したチェックボックスのキャプションがイミディエイトウィドウに表示された
実行結果

狙い通り、選択したチェックボックスのキャプションの文字列をイミディエイトウィンドウに表示させる事ができました。

まとめ

この記事の内容をまとめます

  • チェックボックスは複数の選択を可能にした選択肢を提示するコントロール
  • コントロールはFor Each ~ Nextステートメントでループ処理できる
  • チェックボックスはTrue/FalseのValueプロパティを持つ

今回の記事は以上です。For 文を使う事ですっきりとしたプロシジャにする事ができました。このFor文を使えば、「全選択ボタンを押せば全てのチェックボックスにチェックが入る」や「すべてのチェックボックスにチェックが入っている時に全選択ボタンを押すと全てのチェックが外れる」といった操作も可能です。

一工夫を加えて使い勝手の良いユーザーインターフェースに仕上げていきましょう。

<関連記事>

VBA オプションボタン|ユーザーフォームの使い方

VBAのユーザーフォームでオプションボタンを使う方法について解説します。この記事は非エンジニアの会社員でVBAのツールでユーザーフォームの使い方を調べている方を読者に想定しています。

目次

オプションボタンを使う

まずオプションボタンとは何かについて見ていきましょう。

オプションボタンとは

オプションボタンはユーザーに選択してもらうのに使うものです。選択肢の中からひとつだけ選択するときに使います。丸の横にテキストを入れることができます。いかにも丸の部分をクリックして欲しいようなコントロールですが、テキスト部分もクリックできます。というより丸の部分とテキスト部分で一つのコントロールです。

オプションボタンのイメージ図
オプションボタンは丸の部分とテキストの部分で一つのコントロール

選択肢が2個~3個程度と比較的少ない場合に、視覚的に見やすい事が特徴です。4~10個程度の時はリストボックスやコンボボックスを使う方が良いことが多いように思います。

オプションボタンを実装する

早速実装してみましょう。

ユーザーフォームの設計

オプションボタンをユーザーフォームに挿入するには、ツールボックスから丸の中に点がある絵を選択選択します。

オプションボタンの選択の仕方
オプションボタンはツールボックスの丸の中に点がある絵を選択する

テキストボックスの時のようにユーザーフォームの上にドラッグして、形を決めます。オプションボタンは複数の選択肢からユーザーに選択してもらうことを目的として使うため、今回のサンプルでは3個のオプションボタンと実行ボタンを設置します。

あ
3つのオプションボタンと実行ボタンを設置した

フォームモジュールにイベントプロシジャを記述する

プログラム部分を実装していきます。今回はオブジェクト名を変更していないので、それぞれのオプションボタンのオブジェクト名は、

  • OptionButton1
  • OptionButton2
  • OptionButton3

となっています。実行ボタンもデフォルトのまま、「CommandButton1」です。

’このプロシジャはフォームモジュールに記述する。

Private Sub CommandButton1_Click()

    Select Case True
        Case OptionButton1.Value
            MsgBox "OptionButton1がクリックされました"
        Case OptionButton2.Value
            MsgBox "OptionButton2がクリックされました"
        Case OptionButton3.Value
            MsgBox "OptionButton3がクリックされました"
    End Select
    
    Unload Me
    
End Sub

実行してみると分かりますが、オプションボタンを複数選択することはできません。択一式の選択肢のみに使えます。そこで、次は2つの別の選択肢群があると仮定して、それぞれにオプションボタンで選択肢を作る事ります。

フレームでオプションボタンをグルーピングする

ここでフレームを使います。フレームの役割はフレーム内のコントロールを一つのグループにする事です。フレームで囲むと言うより、フレームの枠の中においたコントロールが一つのグループのイメージです。

お盆の上のコップ乗せるように、フレームの上にオプションボタンなどのコントロールをのせます。

フレームを使うと囲んだ範囲を一つのグループにする事ができる
フレームを使って6つのオプションボタンを2つにグルーピングした

ユーザーフォーム上に6個のオプションボタンが設置されています。フレームがなければ、ひとつのオプションボタンしか選択できませんが、フレームでグルーピングしている為、フレームごとにオプションボタンをひとつずつ選択することができます。

フレームによりカテゴリごとの選択をさせることができる
フレームごとに一つずつオプションボタンを選択することができる

まとめ

  • オプションボタンの目的は少ない選択肢から一つを選択させる事
  • フレームを使うことでオプションボタンをグルーピングできる


オプションボタンとフレームを使った活用方法についての解説は以上です。質問があれば、コメント欄からどうぞ!

<関連記事>

VBA テキストボックスにInitializeで値を設定する|ユーザーフォームの使い方

今回はVBAのユーザーフォームでテキストボックスにデフォルトの値を設定し、ユーザーの使い勝手を高めます。この記事はVBAで自動化ツールを作成している非エンジニアの会社員を読者に想定しています。

目次

ユーザーフォームが表示される事がトリガーのイベントプロシジャInitialize

今回はInitializeというユーザーフォームが開かれたことをトリガーにして実行されるイベントプロシジャを利用します。やりたいことは下記の様な設定をデフォルトで設定することです。

デフォルトで記入例が表示されている
今回のテーマ


それぞれのコントロールのオブジェクト名は下記の通りです。

  • ユーザーフォーム:登録フォームfm
  • ユーザー名のラベル:Label1
  • ユーザーが入力するテキストボックス:入力tb
  • 無効な値が入力されたときのラベル:エラーメッセージ
  • 「登録」のコマンドボタン:登録cb

既に下記のプログラムが作成済みです。このプログラムの意味の詳しい解説は、VBA テキストボックスの基本をご参照下さい。

Private Sub 登録cb_Click()

    Dim 入力された値 As String
    Dim 入力された値の文字数 As Long
    
    入力された値の文字数 = Len(入力tb.Value)
    
    Select Case 入力された値の文字数
        Case 0
            エラーメッセージ.Caption = "ユーザー名が入力されていません。"
            Exit Sub
        Case 1
            エラーメッセージ.Caption = "ユーザー名は2文字以上で入力して下さい。"
            Exit Sub
    End Select

    If IsNumeric(入力tb.Value) Then
        エラーメッセージ.Caption = "数値のみの名前は無効です"
        入力tb.Value = ""
        入力tb.SetFocus
        Exit Sub
    Else
        入力された値 = 入力tb.Value
    End If
    
    エラーメッセージ.Caption = ""
    Sheets(1).Cells(1, 1) = 入力された値
    
End Sub

ユーザーフォームが表示される瞬間にテキストボックスに文字を表示させる

実際にInitializeでユーザーフォームの実装を見て行きます。まずは、Initializeのイベントプロシジャを挿入します。プルダウンリストからUserForm、イベント名はInitializeを選択します。

プルダウンリストからUserFormとInitializeを選択する
Initializeのイベントプロシジャを挿入したところ

Initializeでデフォルト設定を行う

挿入されたプロシジャの中身を作成していきます。

Private Sub UserForm_Initialize()

    入力tb.Value = "例) 山田 ゆん太郎"
    入力tb.ForeColor = &HC0C0C0

End Sub

Initializeはユーザーフォームが表示された瞬間に実行されるイベントなので、初期設定にうってつけです。ユーザーが入力方法に迷わないように記入例を薄く表示させています。入力tb.ForeColor = &HC0C0C0のところがポイントです。薄い灰色にしたいのですが、色の番号が分からないので、プロパティウィンドウで調べます。実際に表示させたい色を選択して色番号を確認します。

プロパティウィンドウで実際に色を選択して、表示される番号をコピペする
プロパティウィンドウで色の番号を調べる。

ForeColorというのがテキストボックスに表示される値の文字色を設定するプロパティ名です。「&H00C0C0C0&」と表示されているので、その部分をコピーして、プログラムの中に貼り付けます。””で囲む必要はありません。すると、エディタが勝手にプログラムの中で使うのに適切な記述「&HC0C0C0」に書き換えてくれます。

【注意事項】
実際はここでデフォルト値を決めても構いません。しかし、私は上のサンプルコードのように初期化で色を設定することをオススメします。

理由は、このテキストボックスはユーザーが入力する場合には通常通り黒い文字を表示したいからです。初期設定の色でしか文字を表示しないのであれば、構いませんが、場合によって表示させる色が異なる場合は、初期設定時に色を変える方がメンテナンス時など、後から見たときに分かりやすいです。

ユーザーフォームを表示させると下の様になります。

デフォルトで記入例が表示されているのでユーザーに優しい
デフォルトで灰色の例が表示されている

選択されたらテキストボックスを空にしつつ文字の色を黒にする

入力しやすいテキストボックスになりました。しかし、このままではユーザーが入力した文字も灰色のままになってしまいます。そこで、ユーザーがテキストボックスを選択したらテキストボックスを空にしつつ、文字の色を黒に変更します。

MouseDownはクリックした瞬間に発動するイベント
入力tbにMouseDownイベントを設定

Private Sub 入力tb_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    入力tb.Value = ""
    入力tb.ForeColor = &H80000008
End Sub

これでユーザーがマウスで入力のためのテキストボックス、入力tbをクリックした瞬間に発動するイベントが完成しました。

マウスではなくTabキーで選択する場合やいきなり文字を打ち込むユーザーがいるかもしれません。キーボードで入力が始まった瞬間にも同様のプロシジャを設定しておきます。

Private Sub 入力tb_Change()
    入力tb.Value = ""
    入力tb.ForeColor = &H80000008
End Sub

これで大分ユーザーフレンドリーなコードになりました。少しの工夫で使いやすさが向上します。皆さんも少しの工夫をしてツールの完成度を高めていきましょう。

【関連記事】
ユーザーフォームを使う3ステップ
テキストボックスの基本|ユーザーフォームの使い方

VBA テキストボックスの基本|ユーザーフォームの使い方

この記事では、ユーザーフォームでテキストボックスを一工夫することによって気の利いたユーザーインタフェースにする事を目指します。エクセルVBAで自動化ツールを作成している非エンジニアの会社員を読者に想定しています。

目次

気の利いたユーザーフォームに仕上げる

今回はシンプルな機能のユーザーフォームに手を加え、誤入力に強いものに仕上げます。サンプルとして用意したユーザーフォームは下の図の通りです。

テキストボックスと登録ボタンのみのシンプルなユーザーフォーム
今回、完成度を高めるユーザーフォーム

ユーザー名を入力してもらい、登録ボタンを押すとA1セルにユーザー名が書き込まれるというシンプルな機能です。

ユーザーフォームを使うメリットを理解する

ユーザーフォームを使うに当たり、そのメリットを把握しておきましょう。

入力を制御できる

VBAで作るマクロツールの基本的な動きは、入力値を受け取り、何かの処理を行い、結果を出力する事です。

入力値を受け取り、何かの処理を行い、出力するイメージ
マクロツールのイメージ

入力値をユーザーに入力してもらう場合、人が作業する以上、意図と違う操作をされてしまう可能性があります。ユーザーフォームを使う事によって、意図せぬ値を入力された時の処理を予めプログラムとして組み込んでおくことができる事がユーザーフォームのメリットです。

使い勝手を向上させられる

もう一つのメリットとして視覚的に分かりやすく、使い勝手のいいツールを作成出来ることです。ユーザーとプログラムをつなぐ部分をユーザーインターフェースと言います。ユーザーインタフェースにメッセージボックスやインプットボックスを使うより細かな設計や細かな挙動のプログラムが可能になる為、使い勝手の良いツールに仕上げることが可能となります。

意図せぬ操作によるエラーを防ぐ

それでは一点目のメリットである意図せぬ操作によるエラーを防ぐ方法を具体的に見て行きます。具体的には、下記の機能を盛り込みます。

  • 数値のみの入力なら再入力を促す
  • ユーザー名を入力するテキストボックスが空欄の状態で登録ボタンを押すと入力を促すテキストを表示出して処理を止める
  • ユーザ-名が1文字なら最低二文字以上でないと登録できない旨のテキストを表示する

まず、上記の3点を盛り込むために設計を考えます。処理の順序としては下記の通りです。

  1. 文字数を判定する
  2. 入力値が文字列かどうか判定
  3. 数値でなければ、文字数に応じて処理分岐
入力データの型を制限する

それでは入力データの方を制限する部分を、入力値の文字数のカウント部分から作成していきます。
◆ 文字数を判定する

Private Sub 登録cb_Click()

    Dim 入力された値の文字数 As Long
    
    入力された値 = 入力tb.Value
    入力された値の文字数 = Len(入力された値)
    
    Select Case 入力された値の文字数
        Case 0
            'ここにテキストボックスが空欄の時の処理
        Case 1
            'ここにテキストボックスの値が1文字時の処理
    End Select
    
End Sub

なお、今回はユーザーフォームの解説なのでそのままSubプロシジャに記述しています。本来は処理内容や判定をする記述を別のSubプロシジャやFunctionプロシジャに記述して、イベントプロシジャはそれらを呼び出すだけ、と言うようなシンプルな記述するような工夫を行います。

想定外の入力の場合、正しい対応を促す

◆文字列の設定されていないラベルを設置する

メッセージボックスを表示させる事によって、正しい入力を促すことも考えられます。しかし、メッセージボックスはユーザーがOKや右上の×を押して消さなければなりませんので、ややストレスがあります。ここは、ユーザーの操作性を考えて、ユーザーフォーム内にテキストを表示させるようにします。

ラベルをユーザーフォーム内に設置します。

エラーがあるときのみ修正を促すラベルを表示させる準備
文字列の設定されていないラベルを設置する

次にラベルのプロパティを設定します。表示⇒プロパティウィンドウでプロパティウィンドウを表示させて下さい。デフォルトでは何も表示させる必要がないため、Captionプロパティは空白にしておきます。目立つように文字の色はにしました。

各種プロパティを設定していく画面
文字列のないラベルのプロパティを設定する

オブジェクト名は分かりやすい様に「エラーメッセージ」としました。

◆ 文字数を判定して処理を分岐する。
次にSelect Case文の中身を作成します。

Private Sub 登録cb_Click()

    Dim 入力された値 As String
    Dim 入力された値の文字数 As Long
    
    入力された値の文字数 = Len(入力tb.Value)
    
    Select Case 入力された値の文字数
        Case 0
            エラーメッセージ.Caption = "ユーザー名が入力されていません。"
            Exit Sub
        Case 1
            エラーメッセージ.Caption = "ユーザー名は2文字以上で入力して下さい。"
            Exit Sub
    End Select
    
End Sub

ポイントはエラーメッセージ.Captionの部分です。プロパティを予め設定しておくのではなく、プログラムの処理の中で設定することができます。この方法で、ユーザーの操作に応じて動的に表示させるメッセージを変えることができます。

もう一点、忘れてはいけないのはExit Subです。ここでイベントプロシジャを終了しないと、その後の処理が実行されてしまうので、不具合のある入力データの場合はExit Subを使ってそれ以上プログラムが進まないようにしておきます。

実行してみるとこのようになります。

正しい入力を促すメッセージが表示された
空白の状態で登録ボタンを押したところ

◆ 入力値が文字列かどうかを確認して適切に処理する
次に123のような数値が入力されると困るので値が文字列かどうかを判定します。

Private Sub 登録cb_Click()

    Dim 入力された値 As String
    Dim 入力された値の文字数 As Long
    
    入力された値の文字数 = Len(入力tb.Value)
    
    Select Case 入力された値の文字数
        Case 0
            エラーメッセージ.Caption = "ユーザー名が入力されていません。"
            Exit Sub
        Case 1
            エラーメッセージ.Caption = "ユーザー名は2文字以上で入力して下さい。"
            Exit Sub
    End Select

    If IsNumeric(入力tb.Value) Then
        エラーメッセージ.Caption = "数値のみの名前は無効です"
        入力tb.Value = ""
        入力tb.SetFocus
        Exit Sub
    Else
        入力された値 = 入力tb.Value
    End If
End Sub

Isnumeric関数を使ってテキストボックス内の値の型が数値かどうかを判定します。数値の場合はIsnumeric関数がTrueを返すので、その時は「数値のみの名前は無効です」と表示させています。

その次の行の、入力tb.Value = "" の記述はテキストボックスの中身を空白に戻しています。この処理は必須ではありません。しかし、ユーザーの気持ちを考えると、入力が受け付けられなかったら、修正する為に入力した値を消すはずです。よって、ユーザーの気持ちになって、再入力がしやすいように値を初期化しておくのが親切です。

さらに、一工夫加えています。入力tb.SetFocusの部分です。登録を押した瞬間に選択されたコントロールが登録ボタンに移ります。これではユーザーが再入力の為にテキストボックスを再度クリックする必要があり、手間が掛かります。と言うわけで、テキストボックスにカーソルを移動しています。このカーソルが当たっている事をフォーカスが当たっていると言います。フォーカスを当てるメソッドがSetFocusです。

ユーザーに配慮したユーザーフォーム
数値を入力して登録を押すと、再入力しやすいように空白に戻してカーソルも戻っている

仕上げを行う

最後にA1セルにユーザーが入力した値を書き込む命令を記述します。

Private Sub 登録cb_Click()

    Dim 入力された値 As String
    Dim 入力された値の文字数 As Long
    
    入力された値の文字数 = Len(入力tb.Value)
    
    Select Case 入力された値の文字数
        Case 0
            エラーメッセージ.Caption = "ユーザー名が入力されていません。"
            Exit Sub
        Case 1
            エラーメッセージ.Caption = "ユーザー名は2文字以上で入力して下さい。"
            Exit Sub
    End Select

    If IsNumeric(入力tb.Value) Then
        エラーメッセージ.Caption = "数値のみの名前は無効です"
        入力tb.Value = ""
        入力tb.SetFocus
        Exit Sub
    Else
        入力された値 = 入力tb.Value
    End If
    
    エラーメッセージ.Caption = ""
    Sheets(1).Cells(1, 1) = 入力された値
    
End Sub

End Subの直前に2行を加えただけです。エラーメッセージ.Caption = ""がポイントです。これがないと、空白や数値のみのエラーが起きた後に修正して有効な値を入力しても、エラーメッセージが残るので不自然です。もしくはUnload Meを使って、ユーザーフォームを終了しても構いません。

このように工夫次第でユーザーフォームはどんどん使い勝手の良いユーザーインターフェースになっていきます。次回の記事テキストボックスにInitializeで値を設定するでは、さらに一工夫加えてユーザーフォームの完成度を高めます。

VBA ユーザーフォームを使う3ステップ

今回はVBAでユーザーフォームを使う方法について解説します。VBAで簡単な自動化ツールの開発をしている会社員を読者として想定しています。初めてユーザーフォームを使う人を対象に解説します。

とりあえず動くモノが作れるところまでいきます。

目次

ユーザーフォームを使う手順

ユーザーフォームを使うには3つのステップを踏みます。下記の3点です。

  1. どんな機能を持たせるのか考える
  2. フォームを設計する
  3. プログラムを書く

プログラムを書くの部分はさらに、

  • イベント内容を記述する
  • ユーザーフォームを表示させる

の2つに分かれます。順番に解説します。

どんな機能を持たせるのか考える

まずはどのような機能を持ったユーザーフォームを作成するのかを考えます。

VBAによるユーザーフォームは後から簡単にボタンやテキストボックスといった部品を追加することができるので、気軽に取り組みましょう。この部品のことを「コントロール」と言います。

今回はユーザー名を登録するフォームを設計することにします。

フォームを設計する

挿入→ユーザーフォームを選択。

ユーザーフォームを選択するには挿入からユーザーフォームを選択する。
ユーザーフォームを選択する

これでユーザーフォームが作成されました。

ユーザーフォームが表示された画面
ユーザーフォームが表示された

ユーザーフォームはオブジェクトとフォームモジュールがセットになったものです。イベントプロシジャを勉強したときにシートにはシートモジュールがくっついていることを学びました。それと同じでユーザーフォームはフォームそのもののオブジェクトとそのオブジェクトを操作するフォームモジュールからなっています。

あとで出てくるので頭に入れておきましょう。

コントロールを追加する

ユーザーフォームにコントロールを追加していきます。今回は入力用のテキストボックスと登録ボタンをもつユーザーフォームを作成します。

コントロールの追加はツールボックスから行います。ツールボックスが表示されていない方は、表示→ツールボックスで表示させることができます。

ツールボックスを表示させる方法
ツールボックスを表示させるには表示→ツールボックスを選択する

コントロールからテキストボックスを選択し、ユーザーフォーム上でドラッグするとドラッグした範囲にテキストボックスが表示されます。同様にしてコマンドボタンも追加します。

ツールボックス内のテキストボックスとコマンドボタンの位置
テキストボックスとコマンドボタン

ここまでの作業で下記の様になっています。

現時点でテキストボックスとコマンドボタンが配置されている
テキストボックスとコマンドボタンを配置したユーザーフォーム

オブジェクト名を設定する

プロパティウィンドウを開いていない人はこの時点で開いておきましょう。プロパティウィンドウの「オブジェクト名」の所にデフォルトでオブジェクト名が入っているので、この時点で書き換えておきます。

後でプログラムを書く時にオブジェクト名を使うことになります。プログラムを書いてからコントロールの名前を変更すると、プログラムとプロパティの両方を修正しなければならなくなるため、この時点で分かりやすい名前をつけておきます。

◆ユーザーフォームのオブジェクト名を設定する

コントロールの名前を変更するにはオブジェクト名の部分を変更する
オブジェクト名をUserForm1から入力フォームに変更した

◆テキストボックスのオブジェクト名を設定する
同様にテキストボックスのオブジェクト名を設定します。

テキストボックスのオブジェクト名を設定した
オブジェクト名を入力tbに設定した
プログラムを書くときにテキストボックスである事が分かりやすい様にText Boxの頭文字を取って「入力tb」と言う名前にしました。

◆コマンドボタンのオブジェクト名を設定する
コマンドボタンも名前をつけておきます。

コマンドボタンのオブジェクト名を設定した
オブジェクト名を登録cbに設定した
登録ボタンなのでCommand Bottonの頭文字を取って「登録cb」という名前にしました。

各種プロパティを設定する

◆ユーザーフォームのプロパティ設定
細かい設定をしていきます。ユーザーフォームの左上の所にUserForm1と書いてあります。ここはCaptionというプロパティの値が表示されます。プロパティウィンドウのCaptionの所を変更します。

フォームの左上の文字を変更するにはCaptionプロパティの値を書き換える
Captionの所に「ユーザー登録フォーム」と書き込んだ
今回はCaptionの部分に「ユーザー登録フォーム」と書き込みました。UserForm1と表示されていたユーザーフォームの部分の文字が変わりました。

◆テキストボックスのプロパティ設定
テキストボックスは今回は細かいプロパティ設定は行いません。工夫するのであれば、予め灰色で「ユーザー名を入力して下さい」などの文字を表示させておいて、ユーザーが入力する際には黒の文字が入力される、と言う事が考えられます。

◆登録ボタンのプロパティ設定
登録ボタンには「登録」の文字列を表示するようにしておきましょう。

Captionでコマンドボタンに表示させる文字列を設定することができる
登録cbのCaptionに「登録」の文字列を設定した

見た目にこだわりたい場合は、Fontで文字を大きくしたり字体を変更することができるので、色々と試してみましょう。

プログラムを書く

ようやくユーザーフォームの設計が終わりました。ここから、それぞれのコントロールが操作された時のプログラムを記述していきます。ちなみにプログラムの内容はフォームモジュールに記述します。フォームモジュールはユーザーフォームというオブジェクトにくっついたモジュールです。

今回は登録cbが押された時のイベントを記述します。フォームモジュールのコードを表示させるには、プロジェクトエクスプローラの左上にあるコードの表示ボタンを押します。

オブジェクト表示画面からコード表示画面に切り替えるボタンの場所
ユーザーフォームのオブジェクト表示画面からコード表示画面に切り替える

Subプロシジャを挿入する

フォームモジュールに書くSubプロシジャはエディタ上部のプルダウンリストから、イベントのトリガーとなるオブジェクト名とトリガーとなる出来事を選択することによって挿入します。

プルダウンリストから選択することによってプロシジャを挿入する
登録cbがクリックされたときのイベントプロシジャを挿入する

今回は登録cbがクリックされたときにイベントを発生させたいので、「登録cb」と「Click」を選択しました。クリック系のコマンドには他にもMouseUpなどがあります。

MouseUpについて簡単に説明します。例えば、ウェブサイト上のリンクをクリックしたらリンク先に飛びますが、あれは左クリックのボタンを押した瞬間に画面が遷移しているのではありません。マウスの左ボタンを放した瞬間にリンク先に画面遷移します。(ピンと来ない方は、リンクを押して離さず待って、しばらくしてから離してみて下さい)それと同じ動きがMouseUpです。

一方Clikは左クリックの押す、と離すのセットです。今回はどちらを選んでも構いません。

Subプロシジャの中身を作成する

サンプルプログラムは下記の通りです。

Private Sub 登録cb_Click()
    
    Sheets(1).Range("A1") = 入力tb.Value
    Unload Me
    MsgBox 入力tb.Value & "を登録しました!"
    
End Sub

一行ずつ解説します。

◆ Private Sub 登録cb_Click()

まず、これはイベントプロシジャです。前述の手順で自動的にSubプロシジャ名が挿入されます。ここで「コントロールのオブジェクト名_イベントトリガー」がプロシジャ名となります。よって、オブジェクト名は大事で。このプロシジャを挿入してからオブジェクト名を変更すると、このプロシジャ名も変更する必要があります。冒頭部分でオブジェクト名は大事、と解説した理由はこの点です。気をつけましょう。

◆ Sheets(1).Range("A1") = 入力tb.Value
一番左のシートのA1セルに、ユーザーがテキストボックスに入力した内容を記入しています。テキストボックスに入力された値はテキストボックスのオブジェクトのValueプロパティに設定されます。そのため、右辺が、入力tb.Valueとなっています。

本当は一度変数に代入する方が筋がいいですが、サンプルコードのわかりやすさを優先して、直接入力しました。

◆ Unload Me
このサンプルコードの肝です。Unloadはユーザーフォームのオブジェクトをロード非表示の状態に戻します。厳密には非表示にするのではなく、そもそも表示させる前の何もしていない状態に戻します。Meはユーザーフォームのことを意味しています。

MsgBox 入力tb.Value & "を登録しました!"
入力tbに入力された内容をメッセージボックスに表示しています。Unload Meの前に記述すると、メッセージボックスがユーザーフォームの上に表示されます。UnloadとMsgBoxのどちらを先に記述するのがいいかは実際に動かしてみて決めましょう。

ユーザーフォームを表示させるプロシジャを記述する

前項まででユーザーフォームのオブジェクトとフォームモジュールの両方を作成する事ができました。つまり、ユーザーフォームが完成しました!

あとはユーザーフォームを表示するSubプロシジャを標準モジュールに作成するだけです。

'これは標準モジュールに書くサンプルです

Sub 入力フォームを表示させる()

    入力フォーム.Show

End Sub

.Showメソッドはユーザーフォームを立ち上げて表示させます。これで、ユーザーフォームを使う事ができました。

VBA エディタの設定を変更する

エクセルVBAでプログラムコードを記述する部分の設定を変更して、使いやすくする方法を簡潔に解説します。

目次

エディタの設定を変更する

VBAのコードを書く為のアプリをVBEと言います。その設定を変更して使いやすくしたり見やすくしたりしていきましょう。

ツールタブからオプションを選択します。

エディタの設定を変更する為の操作
ツールタブからオプションを選択する

これでオプション画面が表示されました。

プログラミングの効率を上げる設定

それではまずプログラミングの効率を上げる設定を行います。

自動構文チェックを外す

編集タブの「自動構文チェック」のチェックボックスを外します。文法的に間違っているときにいちいちメッセージボックスを表示されるのは面倒ですから、外します。文法的に間違っているところは色が変わって表示されるので、メッセージボックスが出る機能は不要です。

構文エラーのたびにメッセージボックスが出る機能を外す
自動構文チェックのチェックボックスを外す

変数の宣言を強制する

「変数の宣言を強制する」のチェックボックスを入れます。変数は慣れてきたら宣言して使います。宣言しないと使えないようにしておけば、構文を間違えて書いて変数だと認識されてしまう、という見つけにくいエラーを防ぐことができます。

自動でOption Explicitが挿入されるようにする
変数の宣言を強制する

コードを見やすくする

「エディターの設定」タブを開いて画面の色や文字の色を好みに変更していきます。

エディタの設定を変更することができる「エディターの設定」タブ
エディタを見やすくする画面

ここは好きなように設定すれば良いです。参考までに私が見やすいと思う設定を紹介します。

コードの表示色以外の設定
  • フォントを見やすくする→フォント名をMeiryo UIに変更する()
  • 少し文字の大きさを大きくする→サイズを12や14に変更する

デフォルトだと文字の線が細く、字も小さくて見づらいので、私はこの設定にしました。

コードの表示色の設定

前景が文字の色、背景がバックの色、インジケーターがインジケーターバーに表示される「⇒」や「○」の色です。

  • 標準コード → 前景:黄、背景:黒、インジケーター:自動
  • 選択された文字 → 前景:黒、背景:黄、インジケーター:自動
  • 構文エラーの文字 → 前景:赤、背景:灰色、インジケーター:自動
  • 次のステートメント → 前景:自動、背景:水色、インジケーター:黄
  • ブレークポイント → 前景:白、背景:茶色、インジケーター:茶色
  • コメント → 前景:灰色、背景:黒、インジケーター:自動
  • キーワード → 前景:水色、背景:黒、インジケーター:自動
  • 識別子 → 前景:白、背景:黒、インジケーター:自動
  • ブックマーク → 前景:自動、背景:自動、インジケーター:水色
  • 呼び出し元 → 前景:自動、背景:自動、インジケーター:緑色

上記を設定すると下の絵のような見た目になります。

見やすく工夫したエディタの画面
全ての設定を行った状態

作業しやすい環境を整えて、ストレスフリーにして効率よくVBA開発ができるようにしましょう!

VBA 三段から四段へのステップアップ ~APIを身に付ける~

VBAプログラミングの勉強で最後に出てくるのがAPIです。エクセルVBAのプログラミングの最後の一山です。これで一通り知らない文法はなくなります!頑張って行きましょう。

この記事はオブジェクト指向やOLEインフォメーションが理解出来ている方(当ブログではVBA三段と定義)を対象読者に想定しています。

VBAのレベルに関しては、レベルについてはExcel VBAの実力(レベル)を定義してみる 初心者~三段をご参照ください。

目次

四段へのステップ

オブジェクト指向やOLEインフォメーションが理解出来ている状態を三段と呼んでいます。Windows APIを利用できることになることが四段へのステップです。三段の皆さんはオブジェクト指向やOLEをマスターしているので、三段と四段の違いはプログラミング能力と言うより、単にやる気とか調べる力の違いではないかと思っています。

オブジェクト指向がしっかりできている

APIの勉強を進めるに当たり、VBAにおけるオブジェクト指向の考え方を復習しておきましょう。

  • 処理の流れと機能を分離する

オブジェクト指向の考え方は処理の流れを記述するプログラムと、実装したい内容を実現するために機能を提供するオブジェクトに分離することです。

エクセルの場合はシートやブックを初めとする既定のオブジェクトが存在しますが、自分で機能を持たせたモノを作る事ができます。その設計図がクラスモジュールです。

クラスモジュールで作成したクラスをオブジェクトとして利用できるようにし、その後実際に使う、処理の流れを記述するのが標準モジュールの本質的な意味合いでした。

オブジェクト指向が分かった上でWindows APIの概念を理解する

Windows APIはWindowsの機能を借りて使う、と言う概念です。

OLEとの違いはクラス(≒VBAの場合はオブジェクト)を借りてくるのではなく、機能を借りてくると言うところです。VBAにおけるオブジェクト指向で機能を実現するのはSubプロシジャやFunctionプロシジャです。APIは○○というライブラリ(機能がたくさん詰まったもの)に入っている××という機能を使います!と宣言して使います。機能なので、SubプロシジャやFunctionプロシジャを呼び出すのと同じようにCallで機能を呼び出します。

調べればなんとかなる、最終的にはできると信じている

他のアプリケーションの名前なんて日常的に使うモノではないので知らなくて当然です。必要な時にピンポイントで使います。と言う事は、知らないことを調べる力が物を言います。

結局三段と四段の違いはプログラミングの実装能力と言うよりは、やりたいことから知らないライブラリや関数名を調べる力の違いと言えます。

「知らないけど調べたらなんとかなる」と思える、信念のようなモノがある状態です。ここまで来れば、実は他のプログラミング言語を学習するときにも「知らないけど調べたらなんとかなる」を貫けるので、頭一つ抜きん出ることができます。

もし周囲にC言語を書く事ができる人がいる方は思い出して欲しいのですが、その人はおそらくC言語しか書けない訳ではないと思います。Javaとか他の言語もできますよね。彼らは得意な言語と好きな言語とできる言語の3種類を持っています。

他言語では調べるのが当たり前なので、調べるたびに、「あ、これってこの言語で書いた方がいいんじゃない」みたいな感じで×言語を増やしていっているのです。

VBAは直感的に分かりやすいため、一度勉強すれば相当できます。調べるのに苦労することは余りありません。つまりVBAから入るとVBA岳になってしまう可能性が高いんですよね。

VBAだけでここまで来れた方は、今こそ殻を破って、「知らなくても調べさえすればOK」の感覚を身に付けましょう!

この状況にたどり着いた状態が四段です。

まとめ

VBAのプログラミングの実装能力を三段から四段にする為のステップは下記の通りです

  1. オブジェクト指向やOLEが使える状態でAPIを勉強する
  2. 知らない事を調べる実力をつける(詳しくある必要はない)
  3. 調べさえすればなんとかなるという感覚を身に付ける

<Windows APIの実装方法関連記事>
VBA Windows APIを使う手順(調べる→宣言する→使う) - Mutable_Yunの業務改善ブログ