0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

業務改善マクロVBAプログラム

Last updated at Posted at 2025-05-19

私たちのチームでは、複数のExcelファイル間で特定の列データを定期的にコピー&ペーストする定型作業に多くの時間を費やしていました。作業対象のファイルやシート、コピーする列の組み合わせは変動的で、手作業による確認と操作が煩雑なだけでなく、ヒューマンエラーも課題でした。この状況を改善すべく、Excel VBAを用いた自動化ツールの開発に取り組みました。
最初に検討したのは、シート上に手動で配置したボタンに、処理対象の列情報を直接設定するシンプルなマクロです。これにより、ボタン一つで指定列のデータ転送が可能となり、一定の効率化は図れました。しかし、対応すべき列の組み合わせが多い場合、ボタンの作成と設定自体が手間となる新たな課題も見えてきました。
そこで、より高度な自動化を目指し、以下の機能を持つマクロ群を開発しました。

'----------------------------------------------------------------------------------
' マクロ名: TransferData_ManualButton
' バージョン: 3.0 改 (手動ボタン設定用シンプル版、説明強化)
' 作成日: 2025/05/19 (最終更新日)
' 作成者: (ユーザー)
'----------------------------------------------------------------------------------
' 【マクロの目的】
'   ユーザーがExcelシート上に手動で配置し、代替テキストに列情報を設定したボタンを
'   クリックすることで、指定された二つのExcelファイル間で、特定の列データを
'   コピー&ペーストする。
'
' 【Kemさんへの使い方&事前準備】
'   1. このVBAコード全体を、マクロを使いたいExcelファイル(.xlsm形式で保存)の
'      標準モジュールにコピペする。
'      (VBE画面を開き、「挿入」→「標準モジュール」で新しいモジュールシートを出す)
'
'   2. Excelの作業シート上に、「挿入」タブ → 「図形」や「テキストボックス」を使って、
'      クリックするための "ボタン" を好きなだけ作成する。
'
'   3. 作成した各ボタン(図形)を右クリックし、「代替テキストの編集」を選択する。
'      (Excelのバージョンによっては「図形の書式設定」ウィンドウの中にあるかも)
'
'   4. 代替テキストの入力欄に、このボタンに担当させたい処理対象列の情報を、
'      以下の【厳密な書式】で入力する:
'      Source:A,Dest:B
'      ↑この書式を絶対守ってくれよな!
'      ・"Source:" と "Dest:" は固定の文字列(大文字小文字は区別しない)。
'      ・コロン ":" の後には、コピー元/貼り付け先の「列のアルファベット1文字」を書く。
'      ・Source情報とDest情報の間は、半角カンマ "," で区切る。
'      ・スペースはあってもなくてもOK (例: "Source: A , Dest: B" でも可)。
'      (例1) コピー元ファイルのC列を、貼り付け先ファイルのD列にコピー → Source:C,Dest:D
'      (例2) コピー元ファイルのA列を、貼り付け先ファイルのA列にコピー → Source:A,Dest:A
'
'   5. 設定が終わったら、再度ボタン(図形)を右クリックし、「マクロの登録」を選択。
'      出てきた一覧から、この `TransferData_ManualButton` マクロを選んで「OK」。
'      これで、ボタンとマクロが紐づけられる。
'
'   6. 【超重要!】このVBAコードの中にある、以下の★マークの箇所を、
'      実際の運用に合わせて自身が確認・編集する必要がある。
'      - コピー元/貼り付け先の「シート名」
'      - コピー元データの「開始行番号」
'      - 貼り付け先データの「開始行番号」
'
'   7. 設定が終わったボタンをクリックすると、マクロが実行される。
'      最初に「コピー元ファイル」、次に「貼り付け先ファイル」を選ぶダイアログが表示される。
'----------------------------------------------------------------------------------
Sub TransferData_ManualButton()

    ' --- ▼▼▼ 1. 変数宣言セクション:マクロで使う道具(変数)を用意する ▼▼▼ ---
    ' これから使う変数を「こういう名前で、こういう種類の情報を入れるよ!」とExcelに教える。
    Dim sourceWb As Workbook          ' コピー元のExcelファイル自体を入れる箱
    Dim sourceWs As Worksheet         ' コピー元のデータがあるシートを入れる箱
    Dim destWb As Workbook            ' 貼り付け先のExcelファイル自体を入れる箱
    Dim destWs As Worksheet           ' データを貼り付けたいシートを入れる箱
    Dim sourceFilePath As Variant     ' コピー元ファイルのフルパス(場所と名前)を入れる箱
    Dim destFilePath As Variant       ' 貼り付け先ファイルのフルパスを入れる箱
    Dim sourceColumnLetter As String  ' コピー元で対象となる列のアルファベット (例: "A")
    Dim destColumnLetter As String    ' 貼り付け先で対象となる列のアルファベット (例: "B")
    Dim copyRange As Range            ' 実際にコピーするセル範囲 (例: A2:A100) を入れる箱
    Dim lastRowSource As Long         ' コピー元列のデータが入っている最終行番号を入れる箱
    Dim firstRowSource As Long        ' コピー元列のデータが始まる行番号を入れる箱 (ヘッダー除く)
    Dim pasteStartCell As Range       ' 貼り付けを開始するセル (例: D9) を入れる箱
    Dim targetSourceSheetName As String ' コピー元ファイルで使うシートの名前を入れる箱
    Dim targetDestSheetName As String   ' 貼り付け先ファイルで使うシートの名前を入れる箱
    Dim buttonShapeName As String     ' 押されたボタン(図形)の名前を一時的に入れる箱
    Dim buttonText As String          ' ボタンの代替テキストの内容を入れる箱
    Dim parts() As String             ' 代替テキストをカンマで区切った部品を入れる配列の箱
    Dim srcPart As String             ' 代替テキストのSource部分を入れる箱
    Dim dstPart As String             ' 代替テキストのDest部分を入れる箱
    ' --- ▲▲▲ 変数宣言セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 2. ボタン情報取得セクション:押されたボタンから指示を読み取る ▼▼▼ ---
    ' マクロがどのボタンから呼ばれたかを確認し、そのボタンの代替テキストから処理情報を抜き出す。
    On Error Resume Next ' いったんエラーが出ても止まらないようにする(後でちゃんとチェックする)
    buttonShapeName = Application.Caller ' マクロを呼び出したものの名前を取得(ボタン名が入るはず)
    If Err.Number <> 0 Then ' もし Application.Caller でエラーが出たら (ボタン以外から実行など)
        On Error GoTo 0 ' エラー監視を通常に戻す
        MsgBox "このマクロは、Excelシート上に配置されたボタン図形から実行してください。", vbExclamation, "実行方法エラー"
        Exit Sub ' マクロをここで終了
    End If
    On Error GoTo ErrorHandler_Manual ' これ以降で何かエラーが起きたら、一番下の ErrorHandler_Manual へジャンプ

    ' 押されたボタン(図形)の代替テキストを取得
    buttonText = ActiveSheet.Shapes(buttonShapeName).AlternativeText

    ' 代替テキストが空っぽじゃないかチェック
    If Trim(buttonText) = "" Then ' Trimで前後のスペースを除いてチェック
        MsgBox "ボタンに処理情報が設定されていません!" & vbCrLf & _
               "ボタンを右クリック →「代替テキストの編集」で、「Source:A,Dest:B」のように設定してください。", vbExclamation, "設定漏れエラー"
        Exit Sub
    End If

    ' 代替テキストを "," (カンマ) で分解して、Source部分とDest部分に分ける
    parts = Split(buttonText, ",")
    If UBound(parts) <> 1 Then GoTo InvalidButtonSetup_Manual ' カンマで2つに分かれなかったら書式エラー

    ' Source部分とDest部分から、それぞれ列名だけを抜き出す
    ' (vbTextCompareは大文字・小文字を区別しない置換)
    srcPart = Trim(Replace(parts(0), "Source:", "", Compare:=vbTextCompare))
    dstPart = Trim(Replace(parts(1), "Dest:", "", Compare:=vbTextCompare))

    ' 列名がちゃんとアルファベット1文字になっているかチェック
    If Len(srcPart) = 1 And Len(dstPart) = 1 And srcPart Like "[A-Z]" And dstPart Like "[A-Z]" Then
        sourceColumnLetter = UCase(srcPart) ' 大文字に統一して変数に格納
        destColumnLetter = UCase(dstPart)   ' 大文字に統一して変数に格納
    Else
InvalidButtonSetup_Manual: ' 代替テキストの書式が不正だった場合のジャンプ先
        MsgBox "ボタンの代替テキストの書式が正しくありません。" & vbCrLf & _
               "「Source:A,Dest:B」の形式で、列名はアルファベット1文字で設定してください。", vbExclamation, "書式エラー"
        Exit Sub
    End If
    ' --- ▲▲▲ ボタン情報取得セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 3. ファイル選択セクション:ユーザーに処理対象ファイルを選んでもらう ▼▼▼ ---
    MsgBox "【ステップ1/2】コピー元のデータが含まれるExcelファイルを選んでください。", vbInformation, "ファイル選択"
    sourceFilePath = Application.GetOpenFilename(FileFilter:="Excel ファイル (*.xlsx; *.xlsm),*.xlsx;*.xlsm", Title:="コピー元ファイルを選択してください")
    If sourceFilePath = False Then ' ファイル選択ダイアログでキャンセルが押されたら
        MsgBox "コピー元ファイルの選択がキャンセルされました。処理を中断します。", vbInformation, "処理中断"
        Exit Sub
    End If

    MsgBox "【ステップ2/2】データを貼り付けたいExcelファイルを選んでください。", vbInformation, "ファイル選択"
    destFilePath = Application.GetOpenFilename(FileFilter:="Excel ファイル (*.xlsx; *.xlsm),*.xlsx;*.xlsm", Title:="貼り付け先ファイルを選択してください")
    If destFilePath = False Then ' ファイル選択ダイアログでキャンセルが押されたら
        MsgBox "貼り付け先ファイルの選択がキャンセルされました。処理を中断します。", vbInformation, "処理中断"
        Exit Sub
    End If
    ' --- ▲▲▲ ファイル選択セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 4. ★★★ 編集箇所:シート名とデータ開始行の設定 ★★★ ▼▼▼ ---
    ' 実際に処理するシート名や、データが何行目から始まるかをここで指定する。
    ' アンタの運用に合わせて、ここの値を毎月とか定期的に書き換えてくれよな!

    targetSourceSheetName = "Sheet1"  ' ← 【要編集】コピー元ファイルで使うシート名を正確に入力 (例: "4月度実績")
    targetDestSheetName = "Sheet1"    ' ← 【要編集】貼り付け先ファイルで使うシート名を正確に入力 (例: "4月度コピー先")
    
    firstRowSource = 2                ' ← 【要編集】コピー元データの実際のデータが始まる行番号 (ヘッダー行の次など)
    Const PASTE_START_ROW As Long = 9 ' ← 【要編集】貼り付け先シートで、データを貼り付け始める行番号
    ' --- ▲▲▲ 編集箇所ここまで ▲▲▲ ---

    ' --- ▼▼▼ 5. ファイルオープンとシート取得セクション:選ばれたファイルとシートを使える状態にする ▼▼▼ ---
    ' 指定されたファイルを開き、中の特定のシートを変数にセットする。
    Application.ScreenUpdating = False ' 処理中の画面のチラつきを抑えて、ちょっとだけ処理を速くするおまじない

    ' コピー元ファイルを開いて、指定シートを取得
    Set sourceWb = Workbooks.Open(sourceFilePath)
    On Error Resume Next ' シート存在確認のため、一時的にエラーを無視
    Set sourceWs = sourceWb.Sheets(targetSourceSheetName)
    On Error GoTo ErrorHandler_Manual ' エラー監視を元に戻す
    If sourceWs Is Nothing Then ' もし指定したシートが見つからなかったら
        MsgBox "コピー元ファイル「" & sourceWb.Name & "」の中に、「" & targetSourceSheetName & "」という名前のシートが見つかりませんでした。" & vbCrLf & _
               "シート名が正しいか、VBAコード内の設定を確認してください。", vbCritical, "シートなしエラー"
        sourceWb.Close SaveChanges:=False ' 開いたファイルは保存せずに閉じる
        GoTo CleanupAndExit_Manual ' 後処理へ
    End If

    ' 貼り付け先ファイルを開いて、指定シートを取得
    Set destWb = Workbooks.Open(destFilePath)
    On Error Resume Next ' シート存在確認のため、一時的にエラーを無視
    Set destWs = destWb.Sheets(targetDestSheetName)
    On Error GoTo ErrorHandler_Manual ' エラー監視を元に戻す
    If destWs Is Nothing Then ' もし指定したシートが見つからなかったら
        MsgBox "貼り付け先ファイル「" & destWb.Name & "」の中に、「" & targetDestSheetName & "」という名前のシートが見つかりませんでした。" & vbCrLf & _
               "シート名が正しいか、VBAコード内の設定を確認してください。", vbCritical, "シートなしエラー"
        If Not sourceWb Is Nothing Then sourceWb.Close SaveChanges:=False ' 開いたコピー元ファイルも保存せずに閉じる
        destWb.Close SaveChanges:=False ' 開いた貼り付け先ファイルも保存せずに閉じる
        GoTo CleanupAndExit_Manual ' 後処理へ
    End If
    ' --- ▲▲▲ ファイルオープンとシート取得セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 6. データコピーセクション:コピー元からデータを引っこ抜く ▼▼▼ ---
    sourceWs.Activate ' コピー元シートをアクティブにする(必須ではないが見た目のため)
    
    ' コピー元列のデータが入っている最終行番号を取得
    lastRowSource = sourceWs.Cells(Rows.Count, sourceColumnLetter).End(xlUp).Row
    
    ' コピー対象のデータが本当にあるかチェック (最終行が開始行より手前ならデータなし)
    If lastRowSource < firstRowSource Then
        MsgBox "コピー元シート「" & sourceWs.Name & "」の " & sourceColumnLetter & " 列には、" & firstRowSource & "行目以降にデータが見当たりませんでした。", vbInformation, "データなし"
        GoTo CleanupAndExit_Manual ' 後処理へ
    End If
    
    ' コピーするセル範囲を設定 (例: A2セルからA列の最終データ行のセルまで)
    Set copyRange = sourceWs.Range(sourceWs.Cells(firstRowSource, sourceColumnLetter), sourceWs.Cells(lastRowSource, sourceColumnLetter))
    
    ' 設定した範囲をクリップボードにコピー
    copyRange.Copy
    ' --- ▲▲▲ データコピーセクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 7. データ貼り付けセクション:コピーしたデータを貼り付け先に置く ▼▼▼ ---
    destWs.Activate ' 貼り付け先シートをアクティブにする(必須ではないが見た目のため)
    
    ' 貼り付けを開始するセルを特定 (例: D列の9行目)
    Set pasteStartCell = destWs.Cells(PASTE_START_ROW, destColumnLetter)
    
    ' 特定したセルに、コピーしたデータを「値と数値の書式」で貼り付け
    ' これにより、計算式自体ではなく、計算結果の値だけが貼り付けられる。
    pasteStartCell.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
    
    Application.CutCopyMode = False ' コピー後に残る点滅選択枠を解除
    ' --- ▲▲▲ データ貼り付けセクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 8. 完了報告セクション:ユーザーに仕事が終わったことを伝える ▼▼▼ ---
    MsgBox "データコピーが完了しました!" & vbCrLf & vbCrLf & _
           "コピー元: 「" & sourceWb.Name & "」の「" & sourceWs.Name & "」シート " & sourceColumnLetter & "列 (" & firstRowSource & "行目~" & lastRowSource & "行目)" & vbCrLf & _
           "貼り付け先: 「" & destWb.Name & "」の「" & destWs.Name & "」シート " & destColumnLetter & "列 (" & PASTE_START_ROW & "行目から)", vbInformation, "処理完了"

' --- ▼▼▼ 9. 後処理セクション (CleanupAndExit_Manual):お片付けをする ▼▼▼ ---
' マクロの最後やエラー発生時に、開いたファイルを閉じたり、変数を解放したりする。
CleanupAndExit_Manual:
    On Error Resume Next ' お片付け中に万が一エラーが出ても、とりあえず最後まで処理を進める
    Application.ScreenUpdating = True ' 画面のチラつき防止を解除

    If Not sourceWb Is Nothing Then ' もしコピー元ファイルが開かれていたら
        sourceWb.Close SaveChanges:=False ' ★重要★ 変更を保存せずに閉じる!
        Set sourceWb = Nothing ' 変数とファイルオブジェクトの繋がりを断つ
    End If
    If Not destWb Is Nothing Then ' もし貼り付け先ファイルが開かれていたら
        destWb.Close SaveChanges:=False ' ★重要★ 変更を保存せずに閉じる!
        Set destWb = Nothing ' 変数とファイルオブジェクトの繋がりを断つ
    End If
    
    ' その他のオブジェクト変数も解放
    Set sourceWs = Nothing
    Set destWs = Nothing
    Set copyRange = Nothing
    Set pasteStartCell = Nothing
    
    On Error GoTo 0 ' エラー監視を通常の状態に戻す
    Exit Sub ' マクロをここで正常終了
' --- ▲▲▲ 後処理セクションここまで ▲▲▲ ---

' --- ▼▼▼ 10. エラー処理セクション (ErrorHandler_Manual):予期せぬエラーが起きた時の避難場所 ▼▼▼ ---
ErrorHandler_Manual:
    MsgBox "申し訳ありません、マクロの処理中に予期せぬエラーが発生しました。" & vbCrLf & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "エラー内容: " & Err.Description, vbCritical, "重大なエラー発生"
    Resume CleanupAndExit_Manual ' エラーが起きても、お片付け処理は実行してから終わる
' --- ▲▲▲ エラー処理セクションここまで ▲▲▲ ---

End Sub
  1. 転送ボタン自動生成マクロ:
利用者が「転送元ファイル」と「転送先ファイル」を指定すると、それぞれのファイルのヘッダー行(1行目や指定行)を読み取り比較します。両ファイルに共通して存在するヘッダー名が見つかった場合、そのヘッダー名を持つ列データを転送するためのボタンを、マクロが格納されたExcelファイルの専用シート上に自動で配置します。各ボタンには、対応する転送元・先の列情報と、両ファイルのフルパス情報が内部的に記録されます。ヘッダー名が一致しない項目については、処理後に一覧で通知する機能も持たせました。
  2. データ転送実行マクロ:
上記マクロによって自動生成されたボタンがクリックされると、このマクロが呼び出されます。ボタンに記録された列情報とファイルパスを元に、実際のデータコピー処理を実行します。ファイル選択は不要となり、利用者は転送先のシート名(必要であれば転送元も)を指定するだけで済みます。
    これらのマクロの導入により、従来の手作業によるデータ転送作業と比較して、準備時間の大幅な短縮と、操作ミスの削減が期待されます。特に、ヘッダー情報を基準に処理対象を動的に決定できるようになったことで、ファイル構成の変更にも柔軟に対応しやすくなりました。今後は、シート名の自動特定や、複数列の一括処理機能なども視野に入れ、さらなる業務効率化を目指していきたいと考えています。

補足

実行ボタン自動作成ver:

'----------------------------------------------------------------------------------
' マクロ名: CreateTransferButtons_Auto_V2
' バージョン: 2.1 (説明強化版)
' 作成日: 2025/05/19 (最終更新日)
' 作成者:  (ユーザー)
'----------------------------------------------------------------------------------
' 【マクロの目的】
'   「貼り付け先ファイル(テンプレート)」と「コピー元ファイル(データソース)」の
'   ヘッダー情報を比較し、一致するヘッダー名を持つ列のデータ転送ボタンを、
'   このマクロが保存されているExcelファイル(マクロブック)の新しいシートに自動生成する。
'   ボタンには、対応するコピー元列・貼り付け先列の情報と、両ファイルのフルパスが
'   埋め込まれ、クリック時にTransferData_CoreEngineマクロを呼び出す。
'   ヘッダー名が一致しない場合は、その旨をユーザーに通知する。
'
' 【ユーザーへの使い方&事前準備】
'   1. このVBAコードと、後述の `TransferData_CoreEngine` 及び `ProcessAllColumns_Auto_V2`
'      のコード全てを、マクロを使いたいExcelファイル(.xlsm形式で保存)の
'      標準モジュールにコピペする。
'
'   2. 【超重要!】このVBAコードの中にある、以下の★マークの箇所を、
'      実際の運用に合わせて自身が確認・編集する必要がある。
'      - 貼り付け先ファイルの「ヘッダーがある行番号」 (destHeaderRow)
'      - コピー元ファイルの「ヘッダーがある行番号」 (sourceHeaderRow)
'
'   3. この `CreateTransferButtons_Auto_V2` マクロを実行する。
'      (例: Alt + F8 でマクロ一覧を出し、これを選んで「実行」)
'
'   4. 最初に「貼り付け先ファイル」、次に「コピー元ファイル」を選ぶダイアログが表示されるので、
'      指示に従ってそれぞれのファイルを選択する。
'
'   5. 処理が終わると、マクロブック内に新しいシート(デフォルト名: "自動生成ボタンシート_V2")が
'      作成され、条件に合ったボタンが配置される。
'      もしヘッダー名が一致しない項目があれば、最後にメッセージで教えてくれる。
'
'   6. 自動生成された個別のボタンをクリックすると、対応するデータが転送される。
'      (ファイル選択はスキップされ、シート名の入力だけ求められる)
'----------------------------------------------------------------------------------
Sub CreateTransferButtons_Auto_V2()

    ' --- ▼▼▼ 1. 変数宣言セクション:マクロで使う道具(変数)を用意する ▼▼▼ ---
    Dim destTemplateFilePath As Variant   ' 貼り付け先テンプレートファイルのフルパスを入れる箱
    Dim sourceDataFilePath As Variant     ' コピー元データファイルのフルパスを入れる箱
    Dim destWb As Workbook, sourceWb As Workbook ' ファイル自体を入れる箱
    Dim destWs As Worksheet, sourceWs As Worksheet   ' シートを入れる箱
    Dim destHeaderRow As Long             ' 貼り付け先ファイルのヘッダーが何行目にあるか
    Dim sourceHeaderRow As Long           ' コピー元ファイルのヘッダーが何行目にあるか
    Dim lastDestCol As Long, lastSourceCol As Long ' ヘッダーがある最終列番号
    Dim c As Long                         ' 列ループ用のカウンター
    
    ' Dictionaryオブジェクト:ヘッダー名(キー)と列アルファベット(アイテム)をペアで記憶する
    Dim destHeaders As Object
    Dim sourceHeaders As Object
    
    Dim btnSheet As Worksheet             ' ボタンを配置するシートを入れる箱
    Dim newBtn As Button                  ' 新しく作るボタンオブジェクトを入れる箱
    Dim btnTop As Double, btnLeft As Double ' ボタンの配置位置(上端、左端)
    Dim btnHeight As Double, btnWidth As Double, btnMargin As Double ' ボタンのサイズと間隔
    Dim errorMessages As String           ' ヘッダー不一致時のエラーメッセージを溜める箱
    Dim buttonsCreatedCount As Long       ' 何個ボタンを作ったかカウントする箱
    ' --- ▲▲▲ 変数宣言セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 2. ★★★ 編集箇所:定数・初期値設定 ★★★ ▼▼▼ ---
    ' ボタン配置シート名や、ヘッダー行の位置などをここで決める。
    ' アンタのファイル構成に合わせて、ここの数字を調整してくれよな!
    Const BTN_SHEET_NAME As String = "自動生成ボタンシート_V2" ' ボタンを作るシートの名前
    
    destHeaderRow = 8     ' ← 【要編集】貼り付け先ファイルのヘッダーがある行番号 (例: 8行目)
    sourceHeaderRow = 1   ' ← 【要編集】コピー元ファイルのヘッダーがある行番号 (例: 1行目)
                          ' 必要なら InputBox でマクロ実行時にユーザーに入力させるのもアリだぜ!
    
    ' ボタンの見た目に関する初期値
    btnTop = 20         ' 最初のボタンの上からの位置
    btnLeft = 20        ' 最初のボタンの左からの位置
    btnHeight = 25      ' ボタンの高さ
    btnMargin = 5       ' ボタン同士の間隔
    errorMessages = ""  ' エラーメッセージは最初は空っぽ
    buttonsCreatedCount = 0 ' ボタン作成数も最初はゼロ
    ' --- ▲▲▲ 定数・初期値設定ここまで ▲▲▲ ---

    ' --- ▼▼▼ 3. Dictionaryオブジェクトの準備 ▼▼▼ ---
    ' ヘッダー情報を効率よく扱うために、Dictionary様にお願いする。
    Set destHeaders = CreateObject("Scripting.Dictionary")
    destHeaders.CompareMode = vbTextCompare ' キーの比較時に大文字・小文字を区別しない設定!超重要!
    Set sourceHeaders = CreateObject("Scripting.Dictionary")
    sourceHeaders.CompareMode = vbTextCompare ' こっちも同様!
    ' --- ▲▲▲ Dictionaryオブジェクトの準備ここまで ▲▲▲ ---

    ' --- ▼▼▼ 4. ユーザーにファイルを選択させるセクション ▼▼▼ ---
    MsgBox "【ステップ1/3】ボタン作成の基になる「貼り付け先ファイル(テンプレート)」を選んでください。" & vbCrLf & _
           "(このファイルの " & destHeaderRow & "行目のヘッダーを基準にします)", vbInformation, "ファイル選択"
    destTemplateFilePath = Application.GetOpenFilename(FileFilter:="Excel ファイル (*.xlsx; *.xlsm),*.xlsx;*.xlsm", Title:="貼り付け先テンプレートファイルを選択")
    If destTemplateFilePath = False Then Exit Sub ' キャンセルされたらマクロ終了

    MsgBox "【ステップ2/3】実際のデータがある「コピー元ファイル(データソース)」を選んでください。" & vbCrLf & _
           "(このファイルの " & sourceHeaderRow & "行目のヘッダーと比較します)", vbInformation, "ファイル選択"
    sourceDataFilePath = Application.GetOpenFilename(FileFilter:="Excel ファイル (*.xlsx; *.xlsm),*.xlsx;*.xlsm", Title:="コピー元データファイルを選択")
    If sourceDataFilePath = False Then Exit Sub ' キャンセルされたらマクロ終了
    ' --- ▲▲▲ ユーザーにファイルを選択させるセクションここまで ▲▲▲ ---

    Application.ScreenUpdating = False ' 画面更新を一時停止して、処理をバックグラウンドで高速に!

    ' --- ▼▼▼ 5. 各ファイルを開き、ヘッダー情報を引っこ抜くセクション ▼▼▼ ---
    On Error GoTo ErrorHandler_CreateV2 ' これ以降でエラーが起きたら ErrorHandler_CreateV2 へジャンプ

    ' ファイルを読み取り専用で開く (間違って変更しちゃうのを防ぐため)
    Set destWb = Workbooks.Open(destTemplateFilePath, ReadOnly:=True)
    Set destWs = destWb.Sheets(1) ' 基本的に1番目のシートを対象とする (必要なら変更可)

    Set sourceWb = Workbooks.Open(sourceDataFilePath, ReadOnly:=True)
    Set sourceWs = sourceWb.Sheets(1) ' こっちも1番目のシートを対象

    ' 貼り付け先ヘッダーを読み込んでDictionaryに格納
    ' 指定されたヘッダー行の1列目からデータがある最後の列までをスキャン
    lastDestCol = destWs.Cells(destHeaderRow, destWs.Columns.Count).End(xlToLeft).Column
    For c = 1 To lastDestCol
        Dim destHeaderText As String
        Dim destColLetter As String
        destHeaderText = Trim(CStr(destWs.Cells(destHeaderRow, c).Value)) ' ヘッダー名を取得し、前後の空白を除去
        destColLetter = Replace(destWs.Cells(1, c).Address(False, False), "1", "") ' セルの列レターを取得 (例: "A", "B")
                                                                                    ' Address(False,False) で "$A$1" -> "A1"
                                                                                    ' Replaceで "1" を消して "A" だけにする
        If destHeaderText <> "" Then ' ヘッダー名が空っぽでなければ
            If Not destHeaders.Exists(destHeaderText) Then ' 同じヘッダー名がまだ登録されてなければ
                destHeaders.Add destHeaderText, destColLetter ' Dictionaryに追加 (キー:ヘッダー名, アイテム:列レター)
            Else
                ' もし同じヘッダー名が複数あった場合の警告 (優しさ)
                errorMessages = errorMessages & "【警告】貼り付け先ファイルに重複ヘッダー「" & destHeaderText & "」がありました。最初の列「" & destHeaders(destHeaderText) & "」を使用します。" & vbCrLf
            End If
        End If
    Next c

    ' コピー元ヘッダーを読み込んでDictionaryに格納 (やってることは貼り付け先とほぼ同じ)
    lastSourceCol = sourceWs.Cells(sourceHeaderRow, sourceWs.Columns.Count).End(xlToLeft).Column
    For c = 1 To lastSourceCol
        Dim sourceHeaderText As String
        Dim sourceColLetter As String
        sourceHeaderText = Trim(CStr(sourceWs.Cells(sourceHeaderRow, c).Value))
        sourceColLetter = Replace(sourceWs.Cells(1, c).Address(False, False), "1", "")
        If sourceHeaderText <> "" Then
            If Not sourceHeaders.Exists(sourceHeaderText) Then
                sourceHeaders.Add sourceHeaderText, sourceColLetter
            Else
                 errorMessages = errorMessages & "【警告】コピー元ファイルに重複ヘッダー「" & sourceHeaderText & "」がありました。最初の列「" & sourceHeaders(sourceHeaderText) & "」を使用します。" & vbCrLf
            End If
        End If
    Next c
    ' --- ▲▲▲ 各ファイルを開き、ヘッダー情報を引っこ抜くセクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 6. ボタン配置用シートの準備セクション ▼▼▼ ---
    ' このマクロブックに、ボタンを置くためのシートを用意する。
    On Error Resume Next ' シートがあるかないか確認するために一時的にエラー無視
    Set btnSheet = ThisWorkbook.Sheets(BTN_SHEET_NAME)
    If btnSheet Is Nothing Then ' もし指定した名前のシートが無かったら
        On Error GoTo ErrorHandler_CreateV2 ' エラー監視を元に戻す
        Set btnSheet = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)) ' 新しいシートを最後に追加
        btnSheet.Name = BTN_SHEET_NAME ' 名前を付ける
    Else ' もしシートが既にあったら
        On Error GoTo ErrorHandler_CreateV2 ' エラー監視を元に戻す
        btnSheet.Cells.ClearContents ' シートの中身を全部消す
        ' 既存のボタンも全部消す (フォームコントロールのボタンの場合)
        Dim oldBtn As Object
        For Each oldBtn In btnSheet.Buttons
            oldBtn.Delete
        Next oldBtn
        ' ActiveXコントロールのボタンの場合は別の消し方が必要になるかも
    End If
    btnSheet.Activate ' 作った(またはクリアした)シートを見えるようにする
    ' --- ▲▲▲ ボタン配置用シートの準備セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 7. ヘッダーを比較しながらボタンを自動生成するメインループ! ▼▼▼ ---
    ' 貼り付け先のヘッダーリストを基準に、一つ一つ見ていく。
    Dim keyDestHeader As Variant ' DictionaryのキーはVariant型で受け取るのがお約束
    For Each keyDestHeader In destHeaders.Keys ' 貼り付け先ヘッダーの全項目についてループ
        Dim currentDestCol As String
        currentDestCol = destHeaders(keyDestHeader) ' 現在の貼り付け先ヘッダーに対応する列レター

        ' コピー元ヘッダーのDictionaryに、同じ名前のヘッダーがあるかチェック!
        If sourceHeaders.Exists(keyDestHeader) Then ' ★ここがミソ!ヘッダー名が一致したら…
            Dim currentSourceCol As String
            currentSourceCol = sourceHeaders(keyDestHeader) ' 対応するコピー元の列レターを取得

            buttonsCreatedCount = buttonsCreatedCount + 1 ' ボタン作った数を一つ増やす

            ' ボタンの幅をヘッダー名の長さに応じてちょっと調整 (見た目のため)
            btnWidth = Len(keyDestHeader) * 7 + 40 ' 文字数に応じて幅を計算
            If btnWidth < 100 Then btnWidth = 100   ' 最低幅
            If btnWidth > 300 Then btnWidth = 300   ' 最大幅

            ' 新しいボタンをシートに追加!
            Set newBtn = btnSheet.Buttons.Add(btnLeft, btnTop, btnWidth, btnHeight)
            With newBtn ' 作ったボタンに対して色々設定していく
                .Caption = keyDestHeader ' ボタンに表示する文字は、共通のヘッダー名!
                .Name = "btnAutoV2_" & Replace(keyDestHeader, " ", "_") ' ボタンの内部名 (スペースはアンダースコアに置換)
                
                ' ★★★ 超・超・重要ポイント! ★★★
                ' ボタンが押された時に実行するマクロとその引数を文字列で作って設定!
                ' TransferData_CoreEngine を呼び出し、引数として
                '   1. コピー元列レター
                '   2. 貼り付け先列レター
                '   3. コピー元ファイルのフルパス (sourceDataFilePath)
                '   4. 貼り付け先ファイルのフルパス (destTemplateFilePath)
                '   5. コピー元シート名 (空文字 "" を渡して、実行時に聞く)
                '   6. 貼り付け先シート名 (空文字 "" を渡して、実行時に聞く)
                ' を渡すように設定している。ファイルパスを埋め込むのがミソ!
                .OnAction = "'TransferData_CoreEngine """ & currentSourceCol & """, """ & currentDestCol & """, """ & CStr(sourceDataFilePath) & """, """ & CStr(destTemplateFilePath) & """, """", """"" '"
                ' ↑最後の "'" は、文字列の中でマクロ名を囲むためのお約束。
                '   文字列中にダブルクォートを入れるために "" と2つ重ねてるのもポイント。
            End With
            
            ' 次のボタンの配置位置を計算 (右にずらす)
            btnLeft = btnLeft + btnWidth + btnMargin
            ' もし右端にはみ出しそうなら、次の行の左端から始める
            If btnLeft + btnWidth > btnSheet.Columns("K").Left Then ' K列あたりを右端の目安に
                btnLeft = 20 ' 左端に戻す
                btnTop = btnTop + btnHeight + btnMargin ' ちょっと下にずらす
            End If
        Else
            ' コピー元に一致するヘッダーがなかった場合のメッセージを溜めておく
            errorMessages = errorMessages & "・貼り付け先のヘッダー「" & keyDestHeader & "」(" & currentDestCol & "列)に対応するヘッダーが、コピー元ファイルに見つかりませんでした。" & vbCrLf
        End If
    Next keyDestHeader ' 次の貼り付け先ヘッダーへ
    ' --- ▲▲▲ ヘッダー比較&ボタン自動生成メインループここまで ▲▲▲ ---

    ' --- ▼▼▼ 8. 「一括実行ボタン」の作成セクション (まだ準備中だけどな!) ▼▼▼ ---
    If buttonsCreatedCount > 0 Then ' もし個別ボタンが1つでも作られてたら
        ' 配置位置を調整 (最後の個別ボタンの下あたりに)
        If btnLeft > 20 Then ' もし最後のボタンが行の途中だったら改行
            btnLeft = 20
            btnTop = btnTop + btnHeight + btnMargin
        End If
        btnTop = btnTop + btnHeight + btnMargin * 2 ' 個別ボタン群から少し離す

        Set newBtn = btnSheet.Buttons.Add(btnLeft, btnTop, 200, btnHeight * 1.2) ' ちょっと大きめのボタン
        With newBtn
            .Caption = "全ての列を一括実行 (※現在準備中)"
            .Name = "btnProcessAll_AutoV2"
            .OnAction = "ProcessAllColumns_Auto_V2" ' 準備中のマクロを呼び出す
        End With
    End If
    ' --- ▲▲▲ 「一括実行ボタン」の作成セクションここまで ▲▲▲ ---

    ' --- ▼▼▼ 9. 後処理セクション:お片付けしてユーザーに報告 ▼▼▼ ---
    If Not destWb Is Nothing Then destWb.Close False ' 読み取り専用で開いたので保存せずに閉じる
    If Not sourceWb Is Nothing Then sourceWb.Close False ' こっちも同様
    Set destWb = Nothing: Set sourceWb = Nothing
    Set destWs = Nothing: Set sourceWs = Nothing
    Set destHeaders = Nothing: Set sourceHeaders = Nothing ' Dictionary様もお役御免
    Set btnSheet = Nothing: Set newBtn = Nothing
    Application.ScreenUpdating = True ' 画面更新を元に戻す

    ' ユーザーへの完了報告メッセージ作成
    Dim finalMessage As String
    If buttonsCreatedCount > 0 Then
        finalMessage = buttonsCreatedCount & " 個のデータ転送ボタンが「" & BTN_SHEET_NAME & "」シートに作成されました!" & vbCrLf
    Else
        finalMessage = "一致するヘッダーが見つからなかったため、データ転送ボタンは作成されませんでした。" & vbCrLf
    End If
    
    If errorMessages <> "" Then ' もしエラーメッセージが溜まってたら
        finalMessage = finalMessage & vbCrLf & "【以下のヘッダーは処理されませんでした】" & vbCrLf & errorMessages
        MsgBox finalMessage, vbExclamation, "ボタン自動生成完了(一部未作成または警告あり)"
    Else
        If buttonsCreatedCount > 0 Then
            MsgBox finalMessage, vbInformation, "ボタン自動生成完了"
        Else
            MsgBox finalMessage, vbInformation, "ボタン自動生成結果"
        End If
    End If
    Exit Sub ' マクロ正常終了
    ' --- ▲▲▲ 後処理セクションここまで ▲▲▲ ---

' --- ▼▼▼ 10. エラー処理セクション (ErrorHandler_CreateV2):予期せぬエラーが起きた時の避難場所 ▼▼▼ ---
ErrorHandler_CreateV2:
    Application.ScreenUpdating = True ' 画面更新は元に戻しておく
    MsgBox "ボタン作成マクロの処理中に予期せぬエラーが発生しました。" & vbCrLf & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "エラー内容: " & Err.Description, vbCritical, "CreateTransferButtons_Auto_V2 エラー"
    ' 開いちゃったファイルがあれば、できるだけ閉じる努力
    On Error Resume Next
    If Not destWb Is Nothing Then destWb.Close False
    If Not sourceWb Is Nothing Then sourceWb.Close False
    Set destHeaders = Nothing: Set sourceHeaders = Nothing
    Set btnSheet = Nothing: Set newBtn = Nothing
    On Error GoTo 0
' --- ▲▲▲ エラー処理セクションここまで ▲▲▲ ---

End Sub

エラーハンドリング

TransferData_ManualButton マクロのエラーケース20選&確認ポイント

VBAマクロ TransferData_ManualButton を使用する際に遭遇する可能性のあるエラーケースと、その解決に役立つ確認ポイントをまとめました。

ボタン設定・呼び出し関連

  1. エラーケース: マクロをボタン図形以外から実行しようとした (例: Alt+F8 で直接実行)。

    • メッセージ例: 「このマクロは、Excelシート上に配置されたボタン図形から実行してください。」
    • 確認ポイント: マクロが割り当てられた図形ボタンをクリックして実行しているか確認してください。
  2. エラーケース: ボタンの代替テキストが空っぽ。

    • メッセージ例: 「ボタンに処理情報が設定されていません!…」
    • 確認ポイント: ボタンを右クリックし、「代替テキストの編集」で Source:A,Dest:B の形式で情報が入力されているか確認してください。
  3. エラーケース: 代替テキストの書式が不正 (カンマがない、コロンがない等)。

    • メッセージ例: 「ボタンの代替テキストの書式が正しくありません。…」
    • 確認ポイント: 代替テキストが厳密に Source:(列),Dest:(列) の形式になっているか(特にカンマ区切り、コロンの位置)確認してください。
  4. エラーケース: 代替テキストの列指定がアルファベット1文字ではない (例: Source:AA, Dest:1)。

    • メッセージ例: 「ボタンの代替テキストの書式が正しくありません。…」
    • 確認ポイント: 列指定が "A"~"Z" (またはExcelの最大有効列) のアルファベット1文字(または有効な列名)になっているか確認してください。(現在のマクロコードでは1文字チェックのみ)
  5. エラーケース: 代替テキストの "Source:" や "Dest:" の文字列が微妙に違う (例: Src:A など)。

    • メッセージ例: (書式エラーとして処理されることが多い)
    • 確認ポイント: "Source:" と "Dest:" の文字列が正確か(大文字・小文字は区別されませんが、スペルミスはNGです)確認してください。

ファイル選択・オープン関連

  1. エラーケース: コピー元/貼り付け先ファイルの選択ダイアログで「キャンセル」を押した。

    • メッセージ例: 「コピー元ファイルの選択がキャンセルされました。…」
    • 確認ポイント: ファイル選択を意図せず中断していないか確認してください。処理を続ける場合は、再度ファイルを選択してください。
  2. エラーケース: 選択したコピー元/貼り付け先ファイルが存在しない、またはパスが不正 (ネットワークドライブが切断など)。

    • メッセージ例: (ファイルオープン時に)エラー番号 1004 など「ファイルが見つかりません。」
    • 確認ポイント: 選択したファイルが実際にその場所に存在し、アクセス可能か確認してください。
  3. エラーケース: 選択したファイルがパスワードで保護されていて開けない。

    • メッセージ例: (ファイルオープン時に)パスワード入力を求められるか、エラーが発生します。
    • 確認ポイント: 対象ファイルにパスワードが設定されていないか確認してください。設定されている場合は解除するか、マクロ側でパスワード入力に対応する改修が必要です (現状未対応)。
  4. エラーケース: 選択したファイルが破損している。

    • メッセージ例: (ファイルオープン時に)「ファイルが破損しているため開けません。」などのメッセージが表示されます。
    • 確認ポイント: ファイルが手動で正常に開けるか確認してください。
  5. エラーケース: 選択したファイルへのアクセス権がない (読み取り権限など)。

    • メッセージ例: (ファイルオープン時に)エラー番号 1004 など「アクセスが拒否されました。」
    • 確認ポイント: ファイルやフォルダのアクセス権設定を確認してください。

シート・データ関連 (VBAコード内の設定と実際のファイル状況の不一致)

  1. エラーケース: VBAコード内の targetSourceSheetName で指定したシートが、選択したコピー元ファイルに存在しない。

    • メッセージ例: 「コピー元ファイル「(ファイル名)」の中に、「(シート名)」という名前のシートが見つかりませんでした。…」
    • 確認ポイント: VBAコード内の targetSourceSheetName の記述と、実際のコピー元ファイルのシート名が完全に一致しているか(スペル、全角/半角スペース等)確認してください。
  2. エラーケース: VBAコード内の targetDestSheetName で指定したシートが、選択した貼り付け先ファイルに存在しない。

    • メッセージ例: 「貼り付け先ファイル「(ファイル名)」の中に、「(シート名)」という名前のシートが見つかりませんでした。…」
    • 確認ポイント: VBAコード内の targetDestSheetName の記述と、実際の貼り付け先ファイルのシート名が完全に一致しているか確認してください。
  3. エラーケース: コピー元シートの指定列 (sourceColumnLetter) に、VBAコード内の firstRowSource 行目以降データが全くない。

    • メッセージ例: 「コピー元シート「(シート名)」の (列名) 列には、(行番号)行目以降にデータが見当たりませんでした。」
    • 確認ポイント: コピー元ファイルの指定シート・列に、指定開始行以降のデータが存在するか、またVBAコード内の firstRowSource の値が適切か確認してください。
  4. エラーケース: コピー元シートが保護されていて、セルのコピーが許可されていない。

    • メッセージ例: エラー番号 1004 など「シートが保護されているため、この操作は実行できません。」
    • 確認ポイント: コピー元シートの保護を解除するか、保護設定でコピー操作を許可してください。
  5. エラーケース: 貼り付け先シートが保護されていて、セルへの書き込みが許可されていない。

    • メッセージ例: エラー番号 1004 など「シートが保護されているため、この操作は実行できません。」
    • 確認ポイント: 貼り付け先シートの保護を解除するか、保護設定で編集操作を許可してください。

その他

  1. エラーケース: 指定された列名がExcelの範囲外 (例: "ZZZ" など、Excelの最大列数を超える)。

    • メッセージ例: (CellsRange オブジェクト使用時に)エラー番号 9「インデックスが有効範囲にありません。」または 1004「アプリケーション定義またはオブジェクト定義のエラーです。」
    • 確認ポイント: ボタンの代替テキストに設定された列アルファベットが、Excelで有効な列の範囲内か確認してください。
  2. エラーケース: firstRowSourcePASTE_START_ROW に不正な行番号 (0以下、またはシートの最大行数を超える) がVBAコード内で設定されている。

    • メッセージ例: エラー番号 9 または 1004。
    • 確認ポイント: VBAコード内の firstRowSourcePASTE_START_ROW の値が、1以上の妥当な行番号か確認してください。
  3. エラーケース: コピーするデータ量が極めて膨大で、メモリ不足になる(非常に稀)。

    • メッセージ例: エラー番号 7「メモリが不足しています。」
    • 確認ポイント: PCのメモリ状況を確認してください。一度に処理するデータ量を減らすなどの対策が必要になる場合があります。
  4. エラーケース: クリップボードが他のアプリケーションによってロックされている、または不安定(非常に稀)。

    • メッセージ例: PasteSpecial メソッドでエラーが発生することがあります。
    • 確認ポイント: PCを再起動してみるか、他の常駐アプリケーションの影響がないか確認してください。
  5. エラーケース: マクロのセキュリティ設定で、マクロの実行が無効になっている。

    • メッセージ例: (マクロ実行ボタンを押しても無反応、またはExcel上部にセキュリティ警告が表示される)
    • 確認ポイント: Excelの「トラストセンター」でマクロのセキュリティ設定を確認し、必要に応じて調整してください。ファイルを開く際に「コンテンツの有効化」ボタンが表示された場合は、クリックしてマクロを有効にしてください。 *

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?