« セルの値を配列に格納して使う | トップページ | Webクエリを秒単位で更新する »

2010年11月27日 (土)

Copy、Pasteメソッドを使わないコピペ

Copy, Pasteメソッドを使わないなら
コピペとは言わないとは思いますが
とりあえずわかりやすいと考え、こう表現しました。

まずは、
なぜワザワザCopy, Pasteを使わないのか?ですが
Copy, Pasteを使うプロシージャを実行しながら
他の作業をしているとき面倒が増えることがあります。

他の作業で手動でコピーをして
ペーストをしたい箇所にカーソルを動かす間に、
裏でExcel VBAがCopy、Pasteをしてしまうと
他の作業で手動でコピーしたデータが
クリップボードからなくなり
また手動でコピーをしなくてはならなくなります。

という理由で個人的には
Excel VBAでCopy、Pasteは使わない方針です。

さて、Copy, Pasteメソッドを使わないコピペとは
どうするのかというと
範囲を直接参照するだけです。

1つのセル同士ならイメージが沸きやすいです。

Range("A1") = Range("A2")

=で結ぶだけです。

複数のセルでもほぼ同じです。

Range("A1:C10") = _
   Range("D1:F10").Value

複数のセル(範囲)だと「.Value」をつけないと
空白のままで値が入りませんでした。

この方法とコピペには1つの違いがあります。
Copy、Pasteはフォーマットと装飾もコピペされるのに対し
直接参照すると装飾はなくなり、
フォーマットは、
反映されたり、されなかったりです。

ん~
フォーマットは、反映されると言うよりは、
値を入れたときにオートフォーマットされるかされないか
といったほうが正しいです。

装飾はともかく
フォーマットは必要ですので、
次のように方法で移します。

Range("A1:C10").NumberFormatLocal = _
   Range("D1:F10").NumberFormatLocal

サンプルコードの前に
下のプロシージャを実行して準備してください。

下のプロシージャを実行して挿入される
シートmacro101127をアクティブにして
その他のプロシージャを実行してください。

macro101127系準備コード:

Sub macro101127a()
'macro101127系準備
'A列に現在から1分ごとの時間を入れる

    Dim i As Integer
    Sheets.Add.Name = "macro101127"
    Sheets("macro101127").Range("A1") = "日時"
    For i = 2 To 10
        Sheets("macro101127").Range("A" & i) = _
            Now + TimeValue("00:0" & i & ":00")
        Sheets("macro101127").Range("A" & i).NumberFormatLocal = _
            "yyyy年mm月dd日(aaa) hh:mm"
    Next i
    Columns.AutoFit
   
    Debug.Print "セルA2のフォーマット:" & Range("A2").NumberFormatLocal
   
End Sub

個別から汎用へ進んでいきます。

最初は1列同士のコピペです。
例として
範囲A2:A10を範囲B2:B10へコピペします。

Copy, Pasteを使わないコピペ1:

Sub macro101127b()
'Copy, Pasteを使わないコピペ
'一列
'元データをコピー先を同じ大きさの範囲を指定
'すべて同一のフォーマット

    '範囲の値を直接指定する
    Range("B2:B10") = Range("A2:A10").Value
   
    'フォーマットを元データと同じにする
    'すべてのセルが同じフォーマットであること
    Range("B2:B10").NumberFormatLocal = _
        Range("A2:A10").NumberFormatLocal
   
End Sub

通常の手動でコピペする時には
左上の1つのセルだけを選択した状態で
ペーストすることが多いと思います。

次のコードはコピー先をそのように指定します。

Copy, Pasteを使わないコピペ2:

Sub macro101127c()
'Copy, Pasteを使わないコピペ
'一列
'一番上のセルを基準にコピペ
'すべて同一のフォーマット

    Dim Range1 As Object 'コピー元を指定
    Dim RCount As Integer 'コピー元行数
    Set Range1 = Range("A2:A10")
    RCount = Range1.Rows.Count
   
    Range("B2").Resize(RCount, 1).Select 'わかりやすく選択
       
    '範囲の値を直接指定する
    Range("B2").Resize(RCount, 1) = Range1.Value
   
    'フォーマットを元データと同じにする
    'すべてのセルが同じフォーマットであること
    Range("B2").Resize(RCount, 1).NumberFormatLocal = _
        Range1.NumberFormatLocal
   
End Sub

上のコードの
コピー元範囲、コピー先の一番上のセルを
それぞれ引数Range1、Range2に指定して実行するように改造したのが
次のコード

Copy, Pasteを使わないコピペ3:

Sub macro101127d(Range1 As Object, Range2 As Object)
'Copy, Pasteを使わないコピペ
'macro101127cを引数付に変更
'Range1 = コピー元範囲
'Range2 = コピー先一番上のセル

    Dim RCount As Integer 'コピー元行数
    RCount = Range1.Rows.Count
   
    Range2.Resize(RCount, 1).Select 'わかりやすく選択
       
    '範囲の値を直接指定する
    Range2.Resize(RCount, 1) = Range1.Value
   
    'フォーマットを元データと同じにする
    'すべてのセルが同じフォーマットであること
    Range2.Resize(RCount, 1).NumberFormatLocal = _
        Range1.NumberFormatLocal
   
End Sub

Sub macro101127dexe()
'macro101127d使用例

    'macro101127d(コピー元範囲, コピー先一番上のセル)
    Call macro101127d(Range("A2:A10"), Range("B2"))
   
End Sub

いままでは1列のみでしたが
次のコードの範囲は複数列でもOKです。

For文を使って1つ1つのセルのフォーマットを指定していくので
すべてバラバラのフォーマットでも大丈夫です。

Copy, Pasteを使わないコピペ4:

Sub macro101127e()
'Copy, Pasteを使わないコピペ
'一番左上のセルを基準にコピペ
'すべて同一のフォーマットである必要はない

    Dim i As Integer, j As Integer
    Dim Range1 As Object 'コピー元を指定
    Dim Range2 As Object 'コピー先左上を指定
    Dim RCount As Integer 'コピー元行数
    Dim CCount As Integer 'コピー元列数
    Set Range1 = Range("A2:B10")
    Set Range2 = Range("C2")
    RCount = Range1.Rows.Count
    CCount = Range1.Columns.Count
   
    Range2.Resize(RCount, CCount).Select 'わかりやすく選択
       
    '範囲の値を直接指定する
    Range2.Resize(RCount, CCount) = Range1.Value
    Range2.Resize(RCount, CCount).Columns.AutoFit
   
    'フォーマットを元データと同じにする
    '1つ1つ参照するのですべて同じでなくてよい
    For i = 1 To RCount
        For j = 1 To CCount
            Range2.Offset(i - 1, j - 1).Select
            Range2.Offset(i - 1, j - 1).NumberFormatLocal = _
                Range1(i, j).NumberFormatLocal
        Next j
    Next i

End Sub

上のコードをまたまた
引数Range1、Range2に指定して実行するように改造したのが
次のコードです。

Copy, Pasteを使わないコピペ5:

Sub CopyPe(Range1 As Object, Range2 As Object)
'Copy, Pasteを使わないコピペ
'一番左上のセルを基準にコピペ
'すべて同一のフォーマットである必要はない
'Range1 = コピー元範囲
'Range2 = コピー先左上のセル

    Dim i As Integer, j As Integer
    Dim RCount As Integer 'コピー元行数
    Dim CCount As Integer 'コピー元列数
    RCount = Range1.Rows.Count
    CCount = Range1.Columns.Count
   
    Range2.Resize(RCount, CCount).Select 'わかりやすく選択
       
    '範囲の値を直接指定する
    Range2.Resize(RCount, CCount) = Range1.Value
    Range2.Resize(RCount, CCount).Columns.AutoFit
   
    'フォーマットを元データと同じにする
    '1つ1つ参照するのですべて同じでなくてよい
    For i = 1 To RCount
        For j = 1 To CCount
            Range2.Offset(i - 1, j - 1).Select
            Range2.Offset(i - 1, j - 1).NumberFormatLocal = _
                Range1(i, j).NumberFormatLocal
        Next j
    Next i

End Sub

Sub macro101127f()
'CopyPe使用例

    Call CopyPe(Range("A2:B10"), Range("C2"))
   
End Sub

Copyメソッドと同じような使い心地を目指しました。

ただフォーマットを指定するところで
1つ1つセルを回しているので
あまり広い範囲のコピペには時間がかかりそうです。

|

« セルの値を配列に格納して使う | トップページ | Webクエリを秒単位で更新する »

コメント

通りすがりのものです。
「クリップボードを経由しない」のが目的であれば、Copyメソッドの引数にコピー先を指定するのがお手軽でいいんじゃないでしょうか。

投稿: h7 | 2011年1月14日 (金) 09時28分

確かに「クリップボードを経由しない」のみが目的なら
~.Copy Destination:=~
でよいことを試行して確認しました。

この記事でのコピペを使わない目的は
Excelでない他のソフト、たとえばメモ帳などで
コピーして他の箇所にペーストするまでの間に
VBAでCopyメソッドを使うと、
他のソフトでペーストしようとしても
何もペーストされなくなってしまう状況を回避することです。

具体的な状況では、
まずメモ帳で適当な文字列をコピーします。
次にVBAで
Range("A1").Copy Destination:=Ragne("A2")
などCopyメソッドを実行します。
メモ帳をアクティブにしてペーストをしてみます。
このとき最初にコピーした適当な文字列はペーストされません。
このような状況なので
またペーストからやり直さなければいけません。

以上のような場面を回避することは
ご指摘の方法ではできませんでした。

投稿: 管理人やむえむ | 2011年1月14日 (金) 16時41分

ごめんなさい、引数を指定すればクリップボードは保護されると勘違いしていましたが、
たしかにクリップボードのデータが消去されているのを確認しました(Excel2000)。
ということは実際にはやはりクリップボード経由で実処理を行っている
(あるいはクリップボードを必ずクリアしてしまう仕様の)ようですね。
お騒がせし失礼しました。勉強になりました。

投稿: h7 | 2011年1月14日 (金) 20時16分

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: Copy、Pasteメソッドを使わないコピペ:

« セルの値を配列に格納して使う | トップページ | Webクエリを秒単位で更新する »