賞状作成用マクロのクラス化(最終回)
先日まで、順位毎の賞状印刷用データを作成することに挑戦したきた。
infoment.hatenablog.com
今日も、先日の続きから。
実は大会当日の朝に突貫で作成したマクロは、もっと作りが粗かった。
しかしそれでも、何とかその日の大会運営を円滑に行うことができた。
考えてみると、仕事を除けば、私の作成したマクロが社会貢献できた
初めての事例ではなかろうか。また嬉しからずや。
ということで、前回までの分で完成としても良いのだが、今後継続して
使用する場合の汎用性を考えて更に作りこみ、改めて先生に渡すことに
した。
今回考慮すべきと考えた点は、以下のとおり。
- 当日実行するマクロは、極力シンプルに 且つ 解り易いものに。
- 賞状のひな形データ有り無しチェックを追加。
- 作成した印刷用データの保存フォルダ有り無しチェックを追加。
- 優勝から敢闘賞まで、全て異なるひな形の指定確認を可能にする。
ただし、二位以降は省略した場合、前の順位と同じひな形を使用する。
以上を踏まえて作成したクラスモジュール(クラス名:Certificate)
Option Explicit ' 順位指定用。 Public Enum enRank en1st en2nd en3rd en4th [_eLast] End Enum ' 印字用ひな形データ格納パス:一位~四位。 Public SrcFilePath_1 As String Public SrcFilePath_2 As String Public SrcFilePath_3 As String Public SrcFilePath_4 As String ' 作成した印字用データ格納用フォルダパス。 Public DstFilePath As String ' 一位~四位の選手の名前がセットされた範囲。 Public PlayerNameRange As Range ' 印刷用ひな形データ格納パス取得。 Private Property Get SrcFilePath() As Variant Dim arr(en1st To en4th) As Variant ' 二位以降は指定が無ければ、前の順位と同じひな形を使用する。 arr(en1st) = SrcFilePath_1 If SrcFilePath_2 = vbNullString Then arr(en2nd) = arr(en1st) Else arr(en2nd) = SrcFilePath_2 If SrcFilePath_3 = vbNullString Then arr(en3rd) = arr(en2nd) Else arr(en3rd) = SrcFilePath_3 If SrcFilePath_4 = vbNullString Then arr(en4th) = arr(en3rd) Else arr(en4th) = SrcFilePath_4 SrcFilePath = arr End Property Private Sub Class_Initialize() ' 一位~四位の選手の名前が入力された範囲を取得。 ' 初期値は、クラスが初期化された際に選択された範囲とする。 ' ※後で上書き可。 Set PlayerNameRange = Selection End Sub Public Property Get CheckValues() As Boolean Dim FSO As Object Set FSO = CreateObject("Scripting.FileSystemObject") Dim i As Long ' 各印字用ひな形データの存在確認。 For i = enRank.en1st To enRank.en4th If Not FSO.FileExists(SrcFilePath(i)) Then CheckValues = False Exit Property End If Next ' 作成した印字用データ格納フォルダの存在確認。 If FSO.FolderExists(DstFilePath) Then CheckValues = True End Property Private Function GetRankName(i As enRank) As String ' 選んだ順で順位を決定。 Select Case i Case en1st: GetRankName = "優勝" Case en2nd: GetRankName = "二位" Case en3rd: GetRankName = "三位" Case en4th: GetRankName = "敢闘賞" End Select End Function Sub MakeCertificate() ' Excelで選んだ人の名前を格納するための配列。 Dim arr As Variant arr = GetPlayerName Dim SrcArray As Variant SrcArray = Array("部門名", "順位", "選手名") ' Microsoft Word *.* Object Libraryを事前に参照設定のこと。 ' 「Wordそのもの」を設定。 Dim objWord As Word.Application Set objWord = CreateObject("Word.Application") objWord.Visible = True ' 置換後の文字列を格納する配列を作成。 Dim DstArray(0 To 2) As Variant ' シート名が学年や男女・形名になっている。 DstArray(0) = EditCategoryName(ActiveSheet.Name) ' Word内の文字列。 Dim docDoc As Word.Document ' 文字列の置換。 Dim objFind As Word.Find Dim i As Long Dim j As Long For i = en1st To UBound(arr) DstArray(1) = GetRankName(i) DstArray(2) = arr(i) ' 原紙ファイルを開く。 Set docDoc = objWord.Documents.Open(SrcFilePath(i)) Set objFind = objWord.Selection.Find ' 順番に文字列を置換。 For j = 0 To 2 objFind.ClearFormatting objFind.Text = SrcArray(j) objFind.Replacement.ClearFormatting objFind.Replacement.Text = DstArray(j) Call objFind.Execute(Replace:=Word.wdReplaceAll) Next ' 名前を付けてWordファイルを保存。 docDoc.SaveAs2 DstFilePath & "\" & Format(i + 1, "00_") & Join(DstArray, "_") & ".docx" ' ファイルを閉じる。 docDoc.Close False Next ' 「Wordそのもの」を終了。 objWord.Quit MsgBox "ファイル作成しました。" End Sub ' 入賞した選手の名前を取得。 Private Function GetPlayerName() As Variant Dim r As Range ' 名前格納用配列。 Dim arr As Variant arr = Array() ' 選んだ順に配列に格納。 ' 団体戦などは3チームしか出ない場合もあるため、配列のサイズは可変とする。 For Each r In PlayerNameRange ' セルが結合されている場合に備えて、空白判定を行う。 If r <> vbNullString Then ReDim Preserve arr(UBound(arr) + 1) ' 余分なスペース文字を除去したのち、配列に格納する。 arr(UBound(arr)) = WorksheetFunction. _ Trim(Replace(r.Value, " ", " ")) End If Next GetPlayerName = arr End Function ' 部門名称を賞状に合わせて編集。 Private Function EditCategoryName(src As String) As String Dim myReg As Object Set myReg = CreateObject("VBScript.RegExp") myReg.Pattern = "(小学|中学|高校|一般)生?([0-90-9]?)年?生?(男子|女子)(団体)?(形|組手)" Dim MC As Object Dim SM As Object If Not myReg.test(src) Then EditCategoryName = src Exit Function End If Set MC = myReg.Execute(src) Set SM = MC(0).SubMatches Dim Dict As Object Set Dict = CreateObject("Scripting.Dictionary") ' 「一般」以外は、「小学生」「中学生」「高校生」で表記統一。 Select Case SM(0) Case "一般": Dict(1) = SM(0) Case Else: Dict(1) = SM(0) & "生" End Select ' 高校生は学年表記無し。 ' 表記は漢数字で「〇年」とする(〇年生としない)。 If SM(0) <> "高校" And SM(1) <> vbNullString Then Dict(1) = Dict(1) & _ WorksheetFunction.Text(SM(1), "[DBNum1]0年") End If ' 男子または女子を追加。 Dict(1) = Dict(1) & SM(2) ' 団体表記があれば追加。 If SM(3) <> vbNullString Then Dict(1) = Dict(1) & SM(3) End If ' 形の部/組手の部 Dict(2) = SM(4) & "の部" EditCategoryName = Join(Dict.Items, " ") End Function
かなり回りくどい部分も出来てしまったが、これにより実際に作成実行する
個所はシンプルにできた。
Sub 賞状作成() With New VBAProject.Certificate ' 優勝者~三位用Wordデータのひな形フルパス。 .SrcFilePath_1 = Sheets(1).Range("B1") ' 敢闘賞用Wordデータのひな形フルパス。 .SrcFilePath_4 = Sheets(1).Range("B2") ' 作成したWordデータの保存先フォルダパス。 .DstFilePath = Sheets(1).Range("B3") ' 上記の内容確認。もし問題なければ賞状作成。 If .CheckValues Then .MakeCertificate Else MsgBox "指定されたデータまたはフォルダが存在しないため、処理を中断します。 " End If End With End Sub
改めて使ってもらい、要望があればまた見直すこととしよう。
というわけで、このシリーズはこれでおしまい。
参考まで。