TL;DR —
Worksheet.Copyは、Add で使うのと同じBefore:=/After:=の位置指定を取りますが、誰もが引っかかる二つの違いがあります。第一に、何も返しません —Set ws = sheet.Copyは書けないので、できたてのコピーはすぐ次の行でActiveSheet経由で掴みます。 第二に、そしてこれが大物ですが、引数なしのws.Copyはブック内でコピーせず、コピーを収めた真新し いブックを作ります。新しいファイルこそが望みでない限り、常にBeforeかAfterを渡してください。
Sub DuplicateTemplate()
Dim src As Worksheet, copy As Worksheet
Set src = ThisWorkbook.Worksheets("Template")
src.Copy After:=ThisWorkbook.Worksheets(Worksheets.Count) ' 末尾に複製する
Set copy = ActiveSheet ' コピーがいまアクティブ
copy.Name = "Template " & Format(Now, "hhmmss") ' すぐにリネームする
End Sub
Worksheet.Copy は、タブを右クリック ▸ シートの移動またはコピー ▸ コピーを作成する のコード版です。
レポート系のマクロが毎月テンプレートから新しいシートを打ち出すのに使います。同時に、シート管理系の中で
いちばん意外なメソッドでもあります。「当たり前」に見える呼び出し — 引数なしの Sheets("Template").Copy
— が、名前から想像するのとはまったく別のことをするからです。
この記事で学べること
- 考え方の軸 —
Copyは Add の双子:同じ位置指定、戻り値なし - ほとんどのマクロを壊す驚き — 引数なしの
Copyは新しいブックを生む - メソッドが何も返さないとき、コピーを参照する方法
- コピーされたシートについてくるもの — 数式、書式、コード、そして定義された名前
Moveが反対の意図でCopyを映し出す仕組み、そして別のブックへコピーする方法
考え方の軸:Copy は Add の双子、ただし戻り値なし
シートの追加とコピーは文法を共有します。どちらも シートがどこに着地するか を言うために Before:= と
After:= を受け取り、どちらも末尾ではなくある位置を既定にします。違いは、Add が新しいシートを手渡す
関数であるのに対し、Copy はまったく何も返さないメソッド だということです。Set ws = src.Copy は
書けません — コンパイルエラーになります。
そこで Excel が、できたての複製を掴む方法をちょうど一つだけ残しています — Copy が走った直後、コピーが
アクティブシート になるのです。ほかの何かがフォーカスを奪う前に、次の行で掴んでください。
src.Copy After:=Worksheets(Worksheets.Count)
Dim copy As Worksheet
Set copy = ActiveSheet ' これがコピー - いま掴む
ここは、ActiveSheet に頼るのがだらしなさではなく正しい、数少ない場面の一つです。Copy は本当に新しい
シートをアクティブなまま残し、それ以上の取っ手がないからです。肝心なのは すぐに やることです — Copy
と Set copy = ActiveSheet のあいだに挟まった Calculate、DoEvents、あるいはイベントハンドラーがフ
ォーカスを動かし、間違ったシートを掴ませることがあります。
ほとんどのマクロを壊す驚き:引数なしの Copy は新しいブックを生む
人を検索エンジンへ走らせる挙動がこれです。引数なしの Sheets("Template").Copy は、現在のブックの中でシ
ートを複製する、と当然のように期待するでしょう。しません。Before も After もない Copy は、シー
ト一枚だけの新しいブックを作り、そこにコピーを置きます。ループで回せば、新しいタブの山ではなく、新し
いウィンドウの山ができあがります。
src.Copy ' ローカルの複製ではない - まるごと新しいブックが現れる
ルールは単純です — ブック内で複製したいなら、常に行き先を渡す。とはいえ、引数なしの形はバグではあ りません — 一枚のシートを独立したファイルとして書き出す のに、VBA じゅうで最もきれいな定番の書き方で す。
src.Copy ' このシートだけの新しいブック
ActiveWorkbook.SaveAs "C:\Reports\September.xlsx", FileFormat:=xlOpenXMLWorkbook
ActiveWorkbook.Close SaveChanges:=False
つまり同じメソッドが、たった一つの引数の有無で二つの意図に仕えます。どちらのつもりかを決め、After の
欠落が「このタブを複製する」を「ブックを四十個開く」に変えてしまわないようにしてください。
コピーされたシートについてくるもの
Copy は値だけでなく オブジェクト を複製します — そしてそれは、多くの人が思い描くより多くを含みま
す。コピーされたシートは、数式、書式、グラフ、図形、条件付き書式、そのシートモジュールのコード、そ
して シート単位で定義された名前 を持ってきます。ここから二つの帰結が生まれます。
- ほかのシートを参照していた数式は、その参照を保ちます。だから同じブック内のコピーは、こっそり元シ ートの隣人を指し返すことがあります — 参照を張り替えたかったのか確認してください。
- 複製された定義名 は定番の副作用です。スコープ付きの名前を持つシートをコピーすると、Excel はすでに 存在する名前について確認を求めるか、あるいは黙って二つ目の、別スコープの名前を作ります。
データ だけが欲しいなら、シートをコピーしてはいけません — 範囲をコピーします。
dst.Range("A1:Z100").Value = src.Range("A1:Z100").Value は、荷物を一切連れずに値を移します。シート全
体のコピーが正しい道具になるのは、テンプレート — レイアウト、数式、コード — をそっくりそのまま再現した
いと意図的に望むときです。
コピーの命名、そして Move が Copy を映し出す仕組み
Excel は複製を Template (2)、Template (3) のように自動命名するので、ほとんど必ずすぐにリネームしま
す。戻り値がないので、Copy の直後の行でアクティブシート経由でリネームし、Add
の記事と同じルールが当てはまります — 31 文字、一意、: \ / ? * [ ] は不可。
Worksheet.Move は Copy の鏡像です。まったく同じ Before:=/After:= 引数を取りますが、シートを
複製するのではなく 移動 させ、行き先のない引数なしの Move も また 新しいブックを開きます — シー
トを現在のブックから丸ごと外へ出すのです。引数の形は同じ、意図は反対です。
src.Move After:=Worksheets(Worksheets.Count) ' 末尾へ移動(複製ではない)
src.Copy To:=Workbooks("Report.xlsx").Worksheets(1) ' 別の開いているブックの中へコピー
別のブックへコピーするには、その Before/After 引数でそのブックのシートを指定します — 両方のファイ
ルが開いている必要があります。メソッド全体を貫く判断はこうです。常に行き先を渡し、コピーは次の行で
ActiveSheet 経由で掴み、コピーがコードと名前を連れてくることを忘れず、引数なしの形に手を伸ばすのは
「新しいブック」が本当の目的のときだけにする。
ExcelMaster の活用
シートのコピーは地雷を隠しています — 引数なしの形が、複製ではなく新しいブックを開くのです — そして二つ の静かな罠も。掴むべき戻り値がないこと、そしてコピーが自分のコードと定義名を引きずってくることです。
ExcelMaster には、意図をそのまま
伝えられます — 「Template シートを末尾に複製して、今日の日付で名前を付けて」あるいは「このシートを独立
したファイルとして書き出して」 — すると、それぞれに正しい形を書きます。ブック内の複製には、位置指定した
Copy に ActiveSheet の受け取りとリネームを添えた形。書き出しには、引数なしの Copy に SaveAs を
足した形。さらに、コピーされるシートが衝突する数式や名前を抱えているときには警告します。ブックとコード
はあなたの手元に残ります。
よくある質問
VBA でワークシートをコピーするには?
行き先を付けて Worksheet.Copy を使います — src.Copy After:=Worksheets(Worksheets.Count) はシートを
末尾に複製します。Copy は何も返さないので、新しいシートは次の行で ActiveSheet 経由で掴みます —
Set copy = ActiveSheet — それからリネームします。常に Before:= か After:= を渡してください。引数
なしの形は別のことをします。
Copy マクロが新しいブックを開いてしまうのはなぜ?
Copy を Before も After も付けずに呼んだからです。引数なしの Worksheet.Copy は、現在のブックの
中で複製しません — コピーを収めた、シート一枚だけの新しいブックを作ります。その場で複製するには行き先
(After:=Worksheets(Worksheets.Count))を渡し、引数なしの形は、シートを独立したファイルとして書き出す
用途に取っておきましょう。
コピーされたシートへの参照を得るには?
Copy に戻り値はないので、Set ws = src.Copy は書けません。代わりに、呼び出しの直後にコピーがアクティ
ブシートになるので、すぐ次の行で Set copy = ActiveSheet として掴みます — Calculate や DoEvents、
イベントハンドラーがフォーカスを動かして間違ったシートを掴ませる前に。
シートを別のブックにコピーするには?
両方のファイルを開いた状態で、位置指定の引数の中で相手のブックのシートを指定します —
src.Copy After:=Workbooks("Report.xlsx").Worksheets(Worksheets.Count)。コピーは数式、書式、コードを連
れていきます。元のブックを参照していた数式には注意してください — 元ファイルを指し返すことがあります。
Copy と Move の違いは?
Worksheet.Copy はシートを複製し、Worksheet.Move はそれを移動させて、元の位置から取り除きます。どち
らも同じ Before:=/After:= 引数を取り、どちらも行き先なしで呼ぶと新しいブックを開きます。複製を打ち
出すには Copy、シートを並べ替えたり抜き出したりするには Move を使います。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-14。
関連ガイド: VBA シートの追加 · VBA シートの削除 · VBA Worksheets · VBA ブックを開く · VBA ThisWorkbook
