
photo credit: jacobchristensen Table card via photopin (license)
みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。
エクセルVBAで請求データ一覧から請求書を自動で作成する方法をシリーズでお伝えしています。
前回はこちらの記事でした。
これで請求書を作るVBAプログラムとしては、まあまあ形になってきたと思いますが、ちょっとコードが長くなってきましたよね。
今回から何回かはちょっと趣向を変えて、今の機能はそのままで書き方をスッキリするテクニックをいくつかお伝えします。
まず注目したいのは、ワークシートです。
実は、ワークシートを取り扱う方法として、これまでは「Worksheet型」のオブジェクト変数を使ってきたのですが、別の方法として「オブジェクト名」で指定する方法というのがあります。
オブジェクト名による方法でワークシートを取り扱うと
- 変数の宣言やセットが不要
- プロシージャやモジュールをまたいでオブジェクト名で指定できる
というメリットがあり、結果としてスッキリ書くことができます。
ということで、今回はエクセルVBAでワークシートをオブジェクト名で取り扱う方法です。
では、いってみましょう!
ワークシートをオブジェクト変数で取り扱う方法
エクセルVBAでワークシートを取り扱う場合、これまでお伝えしてきた方法はこのようなものでした。
Sub シートの取得() Dim wsData As Worksheet Set wsData = ThisWorkbook.Worksheets("請求データ") Debug.Print wsData.Name End Sub
- DimでWorksheet型のオブジェクト変数を宣言
- Setでオブジェクト変数にWorksheetオブジェクトをセット
という流れですね。以下記事でも詳しくお伝えしている通りです。
複数のプロシージャで同じワークシートを取り合う使う方法
複数プロシージャで同じワークシートを取り扱いたいとき、どのようにすれば良いでしょうか?
オブジェクト変数へのセットをする方法をベースとするのであれば、いくつかの選択肢があります。
各プロシージャでワークシートをセットする
まず、最もスタンダードな方法ですが、各プロシージャでワークシートオブジェクトをセットする方法です。
例えば、このような形です。
Sub シートの取得() Dim wsData As Worksheet Set wsData = ThisWorkbook.Worksheets("請求データ") Debug.Print wsData.Name Call シートのセルの値を出力 End Sub
Sub シートのセルの値を出力() Dim wsData As Worksheet Set wsData = ThisWorkbook.Worksheets("請求データ") Debug.Print wsData.Range("A1").Value End Sub
単純ではありますが、何度も同じことを書くのは無駄がある気がします。
また、シート名が変更になったときなどは、二か所とも変更しないといけないので面倒ですよね。
Public変数にワークシートをセットする
次にワークシートを格納するオブジェクト変数をPublic変数とする方法です。
例えば、このようなプログラムです。
Option Explicit Public wsData As Worksheet
Sub シートの取得() Set wsData = ThisWorkbook.Worksheets("請求データ") Debug.Print wsData.Name Call シートのセルの値を出力 End Sub
Sub シートのセルの値を出力() Debug.Print wsData.Range("A1").Value End Sub
Public変数は、どのモジュールまたはプロシージャからでも、同一のものとして使用することができます。
こうすると、最初にセットしてしまったものは、他のモジュールまたはプロシージャに処理が移っても、連続して操作することができるんですね。
以下記事でも説明をしている通りです。
しかしこの方法にもデメリットがあります。
上記のような単純なプロジェクトなら良いのですが、たくさんのコード、たくさんのプロシージャから成るような複雑なプロジェクトになると、そのPublic変数がどんな状態なのかを追いかけるのが大変になってきちゃうのです。
ワークシートを引数として渡す
さて、別の方法としてワークシートを引数として渡すという方法があります。
例えばこのような形です。
Sub シートの取得() Dim wsData As Worksheet Set wsData = ThisWorkbook.Worksheets("請求データ") Debug.Print wsData.Name Call シートのセルの値を出力(wsData) End Sub
Sub シートのセルの値を出力(ByVal ws As Worksheet) Debug.Print ws.Range("A1").Value End Sub
プロシージャを呼び出すときに、wsDataを引数として渡します。そして受け取るときに、そのオブジェクトをwsというオブジェクト変数で受け取っているということですね。
ワークシートを渡してのプロシージャ呼び出しが一回なら良さそうです。
ただ、あちこちのプロシージャを呼び出すと考えると、毎回のようにワークシートを引数に入れるのは、スッキリしないですよね。
ワークシートのオブジェクト名とは
そこで登場する別の方法が「オブジェクト名」です。
オブジェクト名はワークシートに定められている定数のようなもので、どのモジュールまたはプロシージャからでもその名称でワークシートにアクセスすることができます。
オブジェクト名を確認する方法
では、試しに「請求データ」シートのオブジェクト名を確認してみましょう。
まず、プロジェクトエクスプローラーで「Sheet1(請求データ)」を選択した状態で、VBEメニューから「表示」→「プロパティウィンドウ」を選択します。または F4 キーでもOKです。
すると、「請求データ」シートのプロパティウィンドウが開きます。
ウィンドウ内には「(オブジェクト名)」という項目があり、これがまさにオブジェクト名です。
この例では「Sheet1」と設定されていますね。
実は、プロパティウィンドウを開かなくても、オブジェクト名を確認できます。
というのも、プロジェクトエクスプローラーに「Sheet1(請求データ)」と記載されていますね。
まさに、ここでの表示が
となっているので、こちらで確認するほうが簡単です。
のあ、オブジェクト名は、シート名つまりWorksheetオブジェクトのNameプロパティとは全く別モノですので注意して下さいね。
オブジェクト名を使ったプログラム
では、実際にオブジェクト名を使って操作をしてみましょう。
冒頭で紹介したプログラムと同様のことを、オブジェクト名による取り扱いとすると、こんなプログラムになります。
Sub シートの取得() Debug.Print Sheet1.Name Call シートのセルの値を出力 End Sub
Sub シートのセルの値を出力() Debug.Print Sheet1.Range("A1").Value End Sub
…たったこれだけです…!
オブジェクト名は、それこそオブジェクト変数と同じような使い方となります。
そして変数ではないので、宣言もセットも不要なのです。
これは便利ですよね!
オブジェクト名を変更する
さて、オブジェクト名ですがデフォルトでは「Sheet1」とか「Sheet2」といった無味乾燥な名称となっていますが、任意の名称に変更をすることができます。
オブジェクト名を変更するのは簡単で、プロパティウィンドウで「オブジェクト名」の欄にカーソルを当てて編集をするだけです。
これで変数を用いるときと同様に、意味のあるオブジェクト名でシートを取り扱うことができますね。
オブジェクト名を使用した請求書作成プログラム
では、シリーズでお伝えしてきた請求書作成プログラムを、オブジェクト名を使用して書き換えてみましょう。
Option Explicit Sub 請求書作成() Dim i As Long, j As Long, k As Long, n As Long 'For~Nextカウント用整数型変数 Dim dayData As Date '納品日格納用変数 Dim dayCutoff As Date '締月入力用変数 Dim strClient As String '取引先格納用変数 Dim strFile As String 'コピー先パス&ファイル名 Dim rowsData As Long '「請求データ」の行数 Dim rowsClient As Long '「取引先マスタ」の行数 rowsData = wsData.Cells(Rows.Count, 2).End(xlUp).Row '「請求データ」の最後の行数を取得 rowsClient = wsClient.Cells(Rows.Count, 1).End(xlUp).Row '「取引先マスタ」の最後の行数を取得 Dim wsInvoice As Worksheet 'ひな形は別ファイルなのでオブジェクト変数を使う dayCutoff = InputBox("締月を入力してください(例:2015/5)") For n = 2 To rowsClient With wsData If WorksheetFunction.SumIfs( _ .Range("F:F"), _ .Range("A:A"), ">=" & dayCutoff, _ .Range("A:A"), "<" & DateAdd("m", 1, dayCutoff), _ .Range("B:B"), wsClient.Cells(n, 1).Value _ ) > 0 Then strFile = ThisWorkbook.Path & "\" & Format(dayCutoff, "yyyymm") & "_" & wsClient.Cells(n, 1).Value & ".xlsx" 'コピー先ファイル名 FileCopy ThisWorkbook.Path & "\請求書ひな形.xlsx", strFile 'ファイルをコピー Workbooks.Open strFile 'コピーにて作成したファイルを開く Set wsInvoice = ActiveSheet '開いたファイルのワークシートをセット k = 21 '請求書ひな形シート用カウント変数、スタートは21行目 For i = 2 To rowsData 'iは請求データ用のカウント変数、最終値の設定にrowsDataを使う strClient = .Cells(i, 2).Value '現在の行のクライアント名を取得 dayData = .Cells(i, 1).Value '現在の行の納品日を取得 If strClient = wsClient.Cells(n, 1).Value Then If Year(dayData) = Year(dayCutoff) And Month(dayData) = Month(dayCutoff) Then '年が2015でかつ月が5の場合は処理を実行 For j = 1 To 3 '請求データの2+i行目を請求書ひな形の21+i行目に転記 wsInvoice.Cells(k, j).Value = .Cells(i, j + 2).Value Next j k = k + 1 End If End If Next i wsInvoice.Rows(k & ":50").Hidden = True 'データがない行を隠す wsInvoice.Calculate '「請求書ひな形」シートを再計算する wsInvoice.Range("A18").Value = "ご請求金額:" & Format(wsInvoice.Range("D54").Value, "#,##0") & " 円" wsInvoice.Range("D15").Value = DateSerial(Year(dayCutoff), Month(dayCutoff) + 1, 0) '請求日 wsInvoice.Range("D16").Value = DateSerial(Year(dayCutoff), Month(dayCutoff) + 2, 0) 'お支払期限 End If End With Next n End Sub
オブジェクト名を使用することで
- ワークシート用のオブジェクト変数をPublicで宣言
- ワークシートオブジェクトのセット
- シートの初期化をするSubプロシージャ
を削除して書いてみました。このほうが、全体としてスッキリ書けているかと思います。
まとめ
以上、エクセルVBAでワークシートをオブジェクト名で取り扱う方法についてお伝えしました。
シートをオブジェクト名で取り扱うことで
- シートをプロジェクト全体で定数のように一意で指定できる
- 宣言やセットなどのステートメントを省ける
といったメリットがあります。
ワークシートを使用する際は、ぜひこの選択肢も利用できるようにしておいてくださいね。
連載目次:データ一覧から請求書を自動で作る
お仕事において特定のデータ一覧から必要な情報を抽出するということは頻繁にありうると思います。ここではデータ一覧から請求書を作るということを目標に、実務で使えるスキルをまっすぐに身に着けることを目的としています。- 【初心者向けエクセルVBA】データ一覧から請求書を自動で作る
- 【初心者向けエクセルVBA】For~Next文で簡潔にプログラムを書く
- 【初心者向けエクセルVBA】行の数をカウントする&不要な行を隠す
- 【初心者向けエクセルVBA】文字列の連結&Format関数での書式変更
- 【初心者向けエクセルVBA】If~Thenを使った条件分岐の超入門
- 【初心者向けエクセルVBA】Public変数の宣言とSubプロシージャの呼び出し
- 【初心者向けエクセルVBA】InputBoxでの日付入力と月末日の自動算出
- 【初心者向けエクセルVBA】Worksheetのコピーを活用して複数の請求書を作る
- 【初心者向けエクセルVBA】ファイルのコピーを使って取引先別の請求書を作る
- エクセルVBAでDateAdd関数を使って年月を条件としてSumIfs関数を使う方法
- 宣言もセットも不要!エクセルVBAでワークシートをオブジェクト名で取り扱う方法