セルのコピー


マクロ記録の落とし穴

マクロによるセルのコピーは、ビギナーとベテランで最も差が出るコードのひとつです。たとえば、セルA1をセルC2にコピーするコードを考えてみましょう。この操作をマクロ記録すると、次のようなコードが生成されます。

Sub Macro1()
    Range("A1").Select
    Selection.Copy
    Range("C2").Select
    ActiveSheet.Paste
End Sub

なるほど、確かに間違っていませんが、決して美しいコードではありません。このコードを参考にして、Sheet1のセルA1をSheet2のセルC2にコピーするコードを作ってみましょう。おそらく次のようになると思います。

Sub Sample1()
    Worksheets("Sheet1").Select
    Range("A1").Select
    Selection.Copy
    Worksheets("Sheet2").Select
    Range("C2").Select
    ActiveSheet.Paste
    Worksheets("Sheet1").Select
End Sub

Selectの多用は速度的に不利ですし、画面が切り替わるのもわずらわしいです。そもそも、セルをコピーするのに「コピー元を選択」→「選択セルをコピー」→「コピー先を選択」→「選択シートに貼り付け」という手順がナンセンスです。マクロ記録は操作を忠実にコード化しますから、決して最適化されたコードを生成しないという良い例ですね。

マクロ記録で得られたコードを見て「そうか、セルのコピーはCopyを使うのか」とわかったら、すぐにヘルプで確認しなければいけません。Copyは何オブジェクトのメソッドだろう?Copyに引数はないのだろうか?など、マクロ記録のコードからはわからないからです。こうした好奇心を持つことが、VBAマスターへも第一歩なのです。ちなみにヘルプは日本語で書かれています。「わかりにくい」と嘆くより「わかろう」と努力してください。さて、ヘルプでCopyメソッドを調べると、次のような構文が書かれています。

expression.Copy(Destination)
expression   必ず指定します。対象となるRangeオブジェクトを返すオブジェクト式を指定します。
Destination  省略可能です。バリアント型(Variant)の値を使用します。コピー先のセル範囲を指定します。
             この引数を省略すると、クリップボードへコピーされます。

ヘルプを読むコツは「すべてを理解しようと思わない」ことです。書いてあるうちの意味の分かるところだけ読んで、意味の分からない部分は飛ばし読みしてください。たとえば上記の「バリアント型(Variant)の値を使用します」は、おそらく多くの方が正確に理解できないであろう記述です。書いてあることは正しいのですが、これを理解するには、ほかのさまざまな知識が必要です。なので、分からなければ、そこは読み飛ばします。引数Destinationは「省略可能」で「コピー先を指定」できるのか・・・と理解すればいいです。意味が分からなかったところは、今後VBAを学習していけば、自然と理解できるようになります。

さて、ヘルプに書かれている内容に戻りましょう。expressionは、要するにコピー元です。Selection.Copyとか、Range("A1").Copyのように書けという意味です。それより気になるのは引数Destinationです。解説によると、コピー先のセルを指定します と書かれています。Copyメソッドは、コピー元をクリップボードにコピーするだけでなく、同時にコピー先を指定することもできるのです。

マクロ記録で生成されたコードでは、Copyメソッドの引数Destinationが省略されていますので、解説の通りコピー元はクリップボードへコピーされます。そこで次のコードとして、貼り付けのPasteメソッドが必要になってくるのです。

とはいえ、マクロ記録を責めてはいけません。マクロ記録は、行われた操作を忠実にコード化しただけなのですから。では、ベテランはどう書くかというと、Copyメソッドの引数Destinationにコピー先を指定して、次のようにスッキリしたコードを使います。

Sub Sample2()
    Range("A1").Copy Range("C2")
End Sub

もし、Sheet1のセルA1からSheet2のセルC2にコピーする場合も、

Sub Sample3()
    Worksheets("Sheet1").Range("A1").Copy Worksheets("Sheet2").Range("C2")
End Sub

これで終わりです。コードが少ないので高速ですし、修正が容易ですし、ミスが減りますし、可読性が高いですし、良いことばかりです。

なお、Copyメソッドの引数を指定するとき、

Range("A1").Copy Range("C2")

Range("A1").Copy Destination:=Range("C2")

の違いについては、下記ページで解説していますのでご覧ください。

引数(オプション)名って書かなくていいの?

もっと簡単にコピーする

Copyメソッドは、セル全体をコピーします。セル内のデータだけでなく、セルに設定されている書式も含めてセル全体です。ところが、セルをコピーするとき「データだけでいいんだけど・・・」というときもあるでしょう。そんなときは、律儀にCopyメソッドを使わず、次のようにする手もあります。

Sub Sample4()
    Range("C2") = Range("A1")
End Sub

書式は引き継がれませんが、セルのデータはコピーできます。これで十分なケースも多いはずです。いわゆる値貼り付けですね。実務では、セルの値だけをコピーしたい場合が少なくありません。そんなとき「値だけコピーするんだから・・・そうか!形式を選択して貼り付けの"値"を使えばいいのか。うん、手作業でもそうするしな。よし、マクロ記録してみよう。え~と、なになに・・・PasteSpecial・・・なんか、ゴチャゴチャして・・・ま、いっか。マクロ記録されたんだから正しいんだろう。これをそのまま使っちゃえ」などと考えて、ずらずらとPasteSpecialを繰り返している人が、実に多いです。ほら、これを読んでいるあなた。あなたですよ(笑)。こうした方は、次の重要な2つのことを、正しく認識していなかったのでしょうね。

  • セルの値はValueプロパティで表される
  • マクロ記録で、マクロを作ろうとしてはいけない

もし、この方法で、複数セルの値だけをコピーするときは、次のようにValueプロパティを省略せずに指定してください。複数セルの値を操作するとき、Valueプロパティは省略できません。

Sub Sample5()
    Range("C1:D5").Value = Range("A1:B5").Value
End Sub

もちろん、コピー元と貼り付け先は、同じ大きさのセル範囲でなければなりません。