CopySheet|シートを複製して複製後のシートを取得する
- yuji fukami
- 20 時間前
- 読了時間: 6分

この部品でできること
CopySheet は、指定したシートを複製し、複製後のシートを Worksheet オブジェクトとして受け取れるようにするExcel VBAの汎用プロシージャです。
シートを複製して、複製後のシートをそのまま戻り値で受け取れる
複製先の位置(どのシートの後ろに置くか)を指定できる。省略すると一番後ろ
複製元のシートが非表示でも複製できる(一時的に表示してから複製し、元の表示状態に戻す)
標準の Worksheet.Copy メソッドで不足していた「複製後のシートを取得する」「非表示シートにも対応する」という2点を、呼び出し側で意識せずに済むようにまとめた部品です。
使いどころ
テンプレートのシートを複製して、そのシートに続けて値を書き込みたいとき
複製したシートの名前をすぐに変更したいとき
普段は非表示にしているテンプレートシートを、隠したまま複製したいとき
複製処理を含む一連の流れを、With や変数で素直に書きたいとき
コード
使い方・引数
引数は2つです。After は省略可能です。
Sheet(Worksheet)・・・複製元のシート
[After](Worksheet)・・・複製したシートを置く位置(このシートの後ろに置く)。省略時はブックの一番後ろ
戻り値は、複製後のシートです。
呼び出し例は次のとおりです。テンプレートシートを複製し、そのまま名前を付けて値を書き込んでいます。
複製先の位置を指定したい場合は、第2引数にそのシートを渡します。
標準の Worksheet.Copy との違い
Excel VBAには標準で Worksheet.Copy というメソッドがあり、シートの複製自体はこれだけでできます。ただし、実際に使おうとすると2つの不便な点があります。
1. 複製後のシートを受け取れない
Worksheet.Copy は Sub として定義されているため、複製したシートを戻り値として返してくれません。そのため、複製直後のシートを操作したい場合は、次のように書く必要があります。
シートを複製すると、複製されたシートがアクティブになるという性質を利用して ActiveSheet から取得する、というのが定石です。ただ、この書き方だと「なぜ ActiveSheet なのか」を知らない人には意図が伝わりにくく、複製するたびに同じ2行を書くことになります。
CopySheet では、この ActiveSheet からの取得を内部に閉じ込め、戻り値としてシートを返すようにしています。呼び出し側は Set NewSheet = CopySheet(Sheet1) と1行書くだけで済みます。
なお、コードの中で Call Sheet.Copy(After:=After) の直後に DoEvents を入れているのは、複製の処理が終わりきる前に ActiveSheet を参照してしまうのを防ぐためです。
2. 非表示のシートは複製できない
もう1つの問題が、シートの表示状態です。非表示(xlSheetHidden)や、シート見出しの右クリックからは再表示できない状態(xlSheetVeryHidden)のシートに対して Copy を実行すると、実行時エラーになります。
テンプレート用のシートは、利用者が誤って編集しないよう非表示にしておくことがよくあります。そのため、複製のたびに「表示する → 複製する → 元に戻す」という手順を書く必要が出てきます。
CopySheet では、この処理も内部で行っています。
複製前に Sheet.Visible の値を JudgeVisible に控えておく
表示状態でなければ、一時的に xlSheetVisible にする
複製が終わったら、控えておいた元の表示状態に戻す
表示状態を True / False ではなく XlSheetVisibility 型で保持しているため、xlSheetVeryHidden だったシートも、複製後はきちんと xlSheetVeryHidden に戻ります。
依存プロシージャ
このコードは自作の依存プロシージャを持たない、自己完結した部品です。上のコードブロックをそのまま標準モジュールに貼り付ければ動作します。
標準機能を補って部品にするという考え方
この CopySheet は、「標準機能でできることを、あえて自作の部品で包み直している」という点で、汎用プロシージャの作り方の一例になっています。
VBAの標準機能は幅広い用途に対応できるよう作られているぶん、特定の使い方をしようとすると少しだけ足りない、という場面が出てきます。今回の Worksheet.Copy であれば、次の2点がそれにあたります。
複製後のシートを返してくれない(毎回 ActiveSheet から拾う必要がある)
非表示のシートだとエラーになる(毎回、表示状態を切り替える必要がある)
どちらも、呼び出す側で数行足せば解決できる内容です。ただ、その数行を毎回書いていると、次のような問題が出てきます。
本来やりたい処理(テンプレートを複製して値を入れる)に対して、前後の準備コードのほうが目立ってしまう
書き忘れると、非表示シートのときだけエラーになる、といった再現しにくい不具合になる
同じ処理があちこちに散らばり、直すときに全部を探して回ることになる
そこで、「標準機能」と「毎回必要になる前後の処理」をひとまとめにして、1つの部品として切り出します。こうしておくと、呼び出す側は本来やりたいことだけを書けるようになり、非表示シートへの対応も自動的についてきます。
部品にするかどうかの判断は、同じ前後処理を2回以上書いていると気づいた時点で検討するくらいがちょうどよいと思います。また、名前を CopySheet のように標準機能へ寄せておくと、「Worksheet.Copy の代わりに使うもの」だと後から見ても分かりやすくなります。
応用・注意点
複製後のシートの取得に ActiveSheet を使っているため、Application.ScreenUpdating = False にしていても複製したシートがアクティブになる点は変わりませんが、画面のちらつきを抑えたい場合は呼び出し側で ScreenUpdating を制御してください。
After を省略した場合は、複製元シートが属するブック(Sheet.Parent)の一番後ろに複製します。複製元と After に別々のブックのシートを渡すことはできません。
同じ名前のシートは作れないため、複製したシートは「Sheet1 (2)」のような名前になります。名前を決めたい場合は、戻り値のシートに対して Name を設定してください。
同じテンプレートを何枚もまとめて複製したい場合は、一括複製と進捗表示に対応した CopySheets のほうが向いています。1枚だけ複製して続けて操作したいときは CopySheet、決まった枚数を量産したいときは CopySheets、という使い分けができます。
複製したシートを別ブックとして保存したい場合は、SaveSheetAsBook と組み合わせると、テンプレートから個別ファイルを作る処理を短く書けます。
まとめ
CopySheet は、シートを複製して、複製後のシートをそのまま戻り値で受け取れるようにする部品です。標準の Worksheet.Copy に対して「複製後のシートを返す」「非表示シートにも対応する」という2点を補っています。標準機能に少しだけ足りない部分があるとき、その差分を部品として包んでしまうと、呼び出し側のコードは本来の目的だけを書けるようになり、対応漏れによる不具合も防げます。


