はもちくわ

コードについて自分なりの解釈を書いてます。

【ExcelVBA】セルの値だけを消す「ClearContents」の結合セルでの使い方

これは失敗談からの記事なのですが、、、
バイト先で、取引先からExcelファイルで送られてくる入荷予定リストを、所定のフォルダから自動で読み取り、入荷する商品と同じ商品が倉庫のどこにあって、さらに、その場所に収まるかどうか?を判定して入荷一覧表に表示するものをExcelVBAで自動化しました。

これは、在庫状況を可視化するヒートマップがほしいと先に頼まれて作った後、「こんなのもあったら便利かね〜」ぐらいの思いつきで勝手にあとづけで作ったものでしたが、思った以上に需要が出てきたため、誰でも簡単に操作できるように整備したものでした。
この用途は限定されていたので、特にガードは気にせすにデータ出力させていたのですが、稀に想定外の使い方をされることも出てきて、異様に処理スピードがゆ〜〜〜っくりになる事が出てきました。
あまりにも遅くなるので、操作した人から「ごめん。なんか壊しちゃったみたい・・・・」と相談され、重くなる原因を調べてみたら、、、セルの値を消すときに、ClearContents を使わずに""を使っていたため、見た目以上にデータが入り込んでいるのが原因でした。

結局、「これ原因は私ですわ^^;」と謝罪しながら修正することになりました。



私はセルの値を消すときに""をよく使います。表の値をまとめて一気に消すときには、セルの結合配置も考えなくてよいので楽ですからね。それに、それほど大量のデータを出力させることもなかったので気にならなかったんです。多くてもA4用紙に収まる程度でしたから。

でも、""は、人間からみたら空白に見えますが、PCからすれば、「空白」というデータになってしまいます。消したことになりません。
今回のように表示するデータに上限がなければ、意図せずにファイル容量が増えてしまいます。良かれと思って作ったものが逆に迷惑になる。。。なんてことにならないように、みなさんも""の多用は気をつけましょう!(それは私か、、、ははは。)



で、、、ふと思ったのですが、ClearContentsって結合セルが対象だと少しだけ気を使いますよね。
「この操作は結合したセルには行えません」とかExcelから注意されたことありません?(笑)
このエラーメッセージ見て、「結合セルには使えないの??」って真に受けないでくださいね。エラーメッセージが言葉足らずなだけです。結合セルに対して使い方が違ってますよっていうエラーです。
では、何がOKで何がダメなのかを下にまとめていきます!



それでは次の表を例にして説明します。

この薄い黄色になっている部分に値を入れたり消したりするとします。この部分はそれぞれ結合セルになってます。
これ、セルに値を入れるようにVBAにベタ打ちすると、

With ActiveSheet
   .Range("C2")="東京都港区"
   .Range("C3")="山田太郎"
   .Range("C4")="0120-333-333"
   .Range("C5")="e_mail.com"
 End With

と、このようにできます。結合セルでも値を入れるだけなら、結合された端のセルだけ指定すればOKですよね。

えっ?ループ処理の場合も見ます??解説はしませんが(笑)

Dim buf As Variant,i As Integer
buf = Split("東京都港区,山田太郎,0120-333-333,e_mail.com",",")
For i=0 To Ubound(buf)
   ActiveSheet.Cells(i+2,3)=buf(i)
Next i

これで同じ動きになりますかね。試してないですが(笑)

 

で、これを消そうと思ったとき、失敗談であげた""を使うと、

ActiveSheet.Range("C2:C5")=""

この1行だけで解決しちゃいます。一気に端だけ指定すればOKです。
これは入力した値を全部消したわけではなく、すべて空白""に置き換えただけです。
このようにベタ打ちする程度のデータ量なら何も問題ありません。便利だから使えばいいと思います。
でも、ループ処理しなければならないようなデータ量になってくると、先程書いたように、知らない間にファイル容量が大きくなってしまう危険性があります。

それじゃあ、セルの値だけ消す命令、ClearContentsを使えばいいじゃない!ということで、上の指定方法のままで

ActiveSheet.Range("C2:C5").ClearContents

とすると、
「この操作は結合したセルには行えません」
とエラーになります。
では、どのように指定すればよいのかというと、結合セルを割らないように、欠けないように指定してやればいいのです。

今回なら、

ActiveSheet.Range("C2:F5").ClearContents

とします。いくつか例をあげて図解しますと

こんな感じになります。契約書や見積書など書式があって、消したくない場所がある場合は、上の図の上から2番めのように分割して指定することになりますね。分割のときは複数行にしたり、Rangeの中でカンマ区切りにしたりと工夫してください。コードを書くときに短くすればいいってもんでもないですよ。自分があとでわかりやすくて、直しやすい方法を取りましょう!

でも、まあ、、、データ量が少ないものは、""を使ってサクッと解決すればよいかと思います。

あと、ここからおまけです。
値入力でループ処理書きましたので、消すときもやってみますね。
結合範囲が不揃いなうえ、わからないとき、とても便利な命令があります。
この例の表ならば、

Dim i As Integer
i=2
With ActiveSheet
   Do while .Cells(i,2)<>""
      .Cells(i,3).MergeArea.ClearContents
      i=i+1
   Loop
End With

とできます。
このループ処理は、表の項目欄(B列のこと)が、空白を挟むこと無く、表の終わりまで続いているので使えるコードです。これなら結合範囲やデータ数を気にせずに処理できます。2行目以下であればデータ項目を追加してもコードは変えずに動きます。.MergeAreaは便利な命令で、結合しているかどうかの判断をさせたり、住所(座標)をしらべたり、今回のように選択したりできます。しかも!うれしいことに、結合して無いセルが対象になっても、エラーになりません!
こういう融通の効く命令は、一定のルールを表に持たせれば、仕組み化が割と簡単ですね〜。

 

久しぶりに記事書きました。まだ書類管理の記事に手を付けてませんが(笑)

それこそ需要無しなんでまあいいか〜(笑)