VBA開発

セルの結合は厄介?結合で実行結果が異なる【エクセルマクロ】

本サイトで好評な記事がパーツ化です。
パーツ化する事でVBAの開発は楽になりますが、
セルの結合(MergeCells)が原因で、パーツが利用できない場合があります。

パーツ化とは

ExcelVBAマクロ初級者からの脱却が、処理のパーツ化(プロシージャの分割)と考えています。
マクロを作る上で基本機能をパーツ化する事で、開発時間の削減に繋がります。

分かりやすく説明すると、エクセルの「関数」と同様です。
SUM関数であれば セル内に「=SUM(1+2+3)」と記載すれば、セルには「6」と表示されますよね。
値を渡せば正しい値で返ってくる動きです。

エクセル操作に起因する処理をパーツ化していると、セル結合状態によって思わぬ動きをしてしまいます。

結合セルの仕様はわかりにくい

結合セルのValueの保持は、左上のみです。
複数セルにデータがある状態で、結合しようとした時にもポップアップで確認可能です。

 

結合状態のセル左上以外はValueはない為、全てのセルをLoopで検査する場合や、空白セルにデータを入れていく形の処理をする場合、結合セルがあるとマクロが思った通りに動きません。

この仕様が厄介なため、マクロ開発者からは「結合セルを使用するのは辞めろ」と声が上がるわけです。

パーツ化NG例

下記のパーツ化のマクロは、結合セルの影響が出てしまいます。

ExcelVBAマクロ「最終行」「最終列」の判断処理をパーツ化する
ExcelVBAマクロ-他ブック他シートの「最終行」「最終列」取得処理をパーツ化する
ExcelVBAマクロ-ヘッダー行を加味して「最終行」取得処理をパーツ化する

原因

最終行取得処理は、値がある最終行を取得するかたちです。
結合データの場合、値がある場所=左上のセル行を取得してしまいます。

■動作(上記、A列の最終行を取得したい場合)
結合している  → 結合セルを無視し、A1の「1」行目を取得する。
(結合セルのA2の「2」ではない)
結合していない → データがあるセルA1の「1」行目を取得する。

まとめ

結合セルが忌み嫌われるのは、上記のような仕様がわかりづらい為です。私もまったく同感です。しかし、帳票などであれば表の見た目をよくするために、結合は必要です。解決策は表形式の場合は結合セルは使わないや、最終行や最終列を取得するような帳票は結合セルは使わないなどのマクロの組み方が必要です。

VBAマクロを利用する以上、結合セルからは逃げられません。
基本使わない運用にして、余計な不具合は発生しないようにする事が望ましいと考えます。
結合を使用する場合は、仕様の癖や動きを確認し、マクロに影響ないようにしましょう。

結合しているかどうかは、以下で判断可能です。

結合しているかどうか

    Dim rng As Range
    '■MergeArea 結合セルの範囲を取得
    Set rng = Range("A14").MergeArea
    MsgBox rng.Address             '$A$14:$A16
    MsgBox rng.Cells(1).Value      '$A$14のValueを表示
    
    Dim chk As Boolean
    '■MergeArea セルが結合されているかどうか
    chk = Range("A14").MergeCells   '$A$14が結合されていればTrue
    MsgBox chk                      '$A$14されていなければ  False

コメント

タイトルとURLをコピーしました