セル範囲内の空白行や結合にも対応したSortオブジェクトVBA

vbanarabihanieyecatch

エクセルVBA 並び替え 色々なパターンの範囲選択に対応できるVBAコードを設計します。
空白行やセル結合時にも対応できる範囲選択を想定しています。

こんにちは じゅんぱ店長 (@junpa33) です。

VBAを使って、エクセルのセルデータの並び替えを行うツールを作成しています。

特定のデータシートの並び替えを行なうマクロツールではなく、出来るだけ多くのパターンのデータシートを並び替えることの出来るものを目指しています。

ですので、その分、利用者が選択するデータ範囲も、色んなパターンを想定する必要があります。

エクセルが標準で搭載している並び替えツールですと、残念ながらその多様性に対応することは出来ません。

今回作成している並び替えマクロツールでは、選択できる並び替え範囲をもっと柔軟に設定できるようにしていきます。

途中に空白行が存在しても範囲指定を行なえる。」とか、「結合セルがあっても範囲指定できる。」を考えていきます。

並び替えマクロ 記事階層

この記事番号は5番です。

想定される並び替えの選択範囲を類型化する

利用者が使用すると想定される、並び替えの選択範囲を4つのパターンに分類しました。

この4つのパターンの選択は、エクセル並び替えマクロツール利用者に、ユーザーフォーム「ソートナビゲーター」で選択していただきます。

①並び替えのデータ範囲が、一つの塊になっている

エクセル標準の並び替えツールのパターンになります。

標準的に想定されているデータ並び替えのエリアです。

エクセル並び替えマクロツールでも、このエリア設定は自動検出されます。

パターン①概念図

連続したデータで繋がっている部分全てが選択されます。

②並び替え範囲の間に全くの空白行が存在する

空白行を無視する対策が必要です。

エクセル標準の並び替えツールだと、21行目の空白行で並び替え範囲検出が停止します。

エクセル並び替えマクロツールですと、空白行を超えて下のデータ塊も含めることが出来ます。

パターン②概念図

この赤枠のようなエリア設定が可能です。並び替え後の空白行は、並び替えエリアの最下段に移ります。

③空白行で上下を挟まれた、全体の中の一部のデータ範囲

選択範囲のデータはひと塊になるので、①パターンの応用的な範囲設定です。

データシートで、全体の中で空白行で挟まれた中のデータ塊を選択します。

パターン③概念図

赤枠のエリアを選択します。並び替えは赤枠エリアだけで、このエリアの上下のデータ塊は並び替えを行ないません。

④並び替えのデータ範囲は、より大きなデータ塊の一部分

選択範囲はイメージ的には、「全国版の何かのデータ集で、あるテーマ部分で、東京都の新宿区のその特定のテーマについてのデータだけを並び替えたい!」のような

このパターン④を使えば、セル結合データ表に対しても、並び替えが可能になるケースが増えるでしょう。

セル結合の何が並び替えを阻害しているのかというと・・・

並び替え範囲指定内(赤罫線枠内)にセルの結合部分があるからです。

このパターン④の「並び替え範囲部分指定」を利用すれば、セル結合を含まない部分の並び替えが可能になります。

パターン④並び替えの注意点

データ塊の一部分だけの並べ替えを行います。並び替えに際しては、範囲指定内でその内部に、デフォルトの並び順を復元できるデータ番号(数字の昇順)などがデータとして含まれている必要があります。

なので、赤枠内の並び替え後に、元の状態に復元できない場合は、データ全体の内容の信ぴょう性に影響を及ぼす可能性が大きいです。(データを壊すことになります。)

パターン④概念図

赤枠内のみ並び替えを行ないます。赤枠以外では並び替えの影響はありません。

並び替え後の、元並びへの復元機能

「リスタート実行」機能

エクセル並び替えマクロツールには、データの並び替え後にその状態を元に戻す機能を付けています。

ただし、その機能を正常に実行するためには、

必要条件として、並び替えをする元データが、A列にID番号やデータ番号があり昇順に並んでいる必要があります。

この条件を満たしていなければ、データを並び替え以前の状態に戻すことは不可能になります。

また、パターン④の選択時に、『 ” データを壊す可能性がある” 』という警告表示が表示されても実行した並び替えに対しては、この復元機能を利用することはできません。

範囲の選択パターンでマクロを設計 そのVBAコード

基本的に、並び替え範囲の設定はユーザーフォーム「ソートナビゲーター」に、マウスクリックで行います。キーボードからの手入力は基本的に行いません。

マクロツールの利用者が、並び替えを行なうエリア内のセルをマウスクリックで選択し、

プログラム側がCurrentRegionプロパティで、並び替え範囲を掌握します。(すべての範囲選択パターンに対してではないですが)

並び替え範囲の始点チェックのVBAコード

広大なエクセルシートで、並び替えマクロツールの利用者がマウスクリックで選択した1個のセルが、

本当に、その利用者が自分の意志でデータの並び替えをしようとしている、選択範囲の始点セルか?

なんて、こちらでは分かるはずもありません。

まさにそこは、「確かにそのセルを選択しました。」という、信じることでしかありません。

とは言うものの、最低限のエラーチェックは出来るようにVBAコードを組み立てておきます。

並び替えのデータエリアを把握

Functionプロシージャーを使用します。

メッセージボックスで始点セルの選択を促します。選択されなければプロシージャーを終了します。

ここでプロシージャーを終了しても、親のプロシージャーに戻ってVBAコードは実行され続けてしまいますので、親プロシージャーに戻すときにエラー終了の信号を付けて戻します。

親プロシージャーはそのエラー信号を受けて自身を終了させることになります。

利用者がマウスクリックした並び替え始点セルが、確かにデータエリア全体の中にあるかどうかをプログラムがチェックします。

先回紹介した「データシート把握」プロシージャーから取り出したRangeオブジェクト変数「ADRange」内に今回取り出したRangeオブジェクト変数「STRC」が含まれていればコード通過、含まれていなければエラー停止します。

内包するかどうかの判別はVBA関数の「Intersect」で判定しています。

VBA
'並び替えデータエリア把握

Function STRC() As Range

        ErEnd = False
        
        Set STRC = Nothing
        On Error Resume Next
        Set STRC = Application.InputBox("見出し行も含めて並び替え" & _
            "ブロックで" & vbCrLf & "始点となるセルを指定して" & _
            "ください。", Title:="始まりのセル指定", Type:=8)
        If Not STRC Is Nothing Then
            STRC.Activate
        End If
        If Err.Number > 0 Then
            MsgBox "キャンセルされました。終了します。"
            ErEnd = True
        Exit Function
        End If
        On Error GoTo 0
        STRCr = STRC.Row
        STRCc = STRC.Column
        If Application.Intersect(ADRange, STRC) Is Nothing Then
            MsgBox "シートのデータ範囲外のセルを指定しました。" _
                & vbCrLf & "再指定してください。", _
                vbExclamation, "再指定"
            ErEnd = True
            Exit Function
        End If
End Function

選択範囲パターン①のVBAコード

この選択範囲のパターンが一番シンプルなVBAコードになります。

並び替えのデータ範囲が一つの塊

先の「並び替えのデータエリアを把握」で取り出したRangeオブジェクト変数「STRC」を使って、それが含まれる範囲をCurrentRegionで取得します。

この取得した選択範囲のエリアをRangeオブジェクト変数「SortAreaA」に代入します。

VBA
Function SortAreaA() As Range
        On Error Resume Next
        Set SortAreaA = STRC.CurrentRegion
        If ErEnd = True Then
            MsgBox "この操作は、条件設定の不備により実行されません。"
            Exit Function
        End If
        SortAreaA.Select
        On Error GoTo 0
End Function

選択範囲パターン②のVBAコード

並び替えするデータの選択範囲の中に空白行がある場合です。

並び替え範囲の選択の指定方法は、

最上段のデータブロックの始点セルは既出の変数「ADRange」で押さえることが出来ていますので、並び替えデータブロックの最下段の終点セルを押さえることで可能になります。

並び替え範囲の間に全くの空白行が存在する

利用者に、インプットボックスで最下段のデータブロックの中の一つのセルをクリックしてもらいます。

そのクリックされたセルが確かにデータエリア全体の中にあるかどうかをIntersect関数でチェックします。

CurrenRegionから最下段データブロックの終点セルを取得します。

始点セルから終点セルまでの並び替え範囲をRangeオブジェクト変数「SortAreaB」に代入します。

VBA
Function SortAreaB() As Range
    Dim SortAreaAn, LDB, LDBR As Range
    Dim LDBEr, LDBEc As Long
        On Error Resume Next
        Set LDB = Application.InputBox("並び替えする最後尾のデータ" & _
            "ブロック内で、" & vbCrLf & "いずれかのセルをクリック" & _
            "してください。" & vbCrLf & "セル位置に基づいて検索" & _
            "エリアをセットします。" & vbCrLf & " " & vbCrLf & _
            "セルを置き直しする場合は「キャンセル」を選択してくだ" & _
            "さい。", Title:="最後尾データブロックの指定", Type:=8)
        If Not LDB Is Nothing Then
            LDB.Activate
        End If
        If Err.Number > 0 Then
            MsgBox "キャンセルされました。終了します。"
            ErEnd = True
            Exit Function
        End If
        On Error GoTo 0
        Set LDBR = LDB.CurrentRegion
        LDBEr = LDBR.Row + LDBR.CurrentRegion.Rows.Count - 1
        LDBEc = LDBR.Column + LDBR.CurrentRegion.Columns.Count - 1
        If Application.Intersect(ADRange, LDBR) Is Nothing Then
           MsgBox "シートのデータ範囲外のセルを指定しました。" _
                    & vbCrLf & "再指定してください。", _
                    vbExclamation, "再指定"
           ErEnd = True
           Exit Function
        End If
        Set SortAreaB = Range(Cells(ADRange.Row, ADRange.Column) _
            , Cells(LDBEr, LDBEc))
        SortAreaB.Select
End Function

選択範囲パターン③のVBAコード

上下を空白行で挟まれたエリアの並び替えの場合の想定です。

並び替えを行なう範囲の中のいずれかのセルを選択することでその並び替え範囲を特定します。

空白行で上下を挟まれた、全体の中の一部のデータ範囲

利用者に、インプットボックスで並び替えをするデータブロックの中の一つのセルをクリックしてもらいます。

そのクリックされたセルが確かにデータエリア全体の中にあるかどうかをIntersect関数でチェックします。

CurrenRegionから並び替え範囲を取得します。

その並び替え範囲をRangeオブジェクト変数「SortAreaC」に代入します。

VBA
Function SortAreaC() As Range
    Dim LDB2, LDB2R As Range
        On Error Resume Next
        Set LDB2 = Application.InputBox("並び替えするデータ" & _
        "ブロック内で、" & vbCrLf & "いずれかのセルをクリック" & _
        "してください。" & vbCrLf & "セル位置に基づいて検索" & _
        "エリアをセットします。" & vbCrLf & " " & vbCrLf & "セル" & _
        "を置き直しする場合は「キャンセル」を選択してください。", _
        Title:="データブロックの指定", Type:=8)
        If Not LDB2 Is Nothing Then
            LDB2.Activate
        End If
        If Err.Number > 0 Then
            MsgBox "キャンセルされました。終了します。"
            ErEnd = True
        Exit Function
        End If
        On Error GoTo 0
        Set LDB2R = LDB2.CurrentRegion
        If Application.Intersect(ADRange, LDB2R) Is Nothing Then
           MsgBox "シートのデータ範囲外のセルを指定しました。" _
           & vbCrLf & "再指定してください。", vbExclamation, "再指定"
           ErEnd = True
           Exit Function
        End If
        Set SortAreaC = LDB2.CurrentRegion
        SortAreaC.Select
End Function

選択範囲パターン④のVBAコード

利用者によって、この選択範囲パターンが選択されると、まず「並び替え範囲部分指定」プロシージャーが呼び出され、Rangeオブジェクト変数「InpAreaV」に並び替え範囲が代入されます。

その変数「InpAreaV」が、このFunctionプロシージャーによって「SortAreaD」という4番目の範囲指定の変数として格納されます。

並び替えのデータ範囲は、より大きなデータエリア塊の一部分

並び替え範囲のRangeオブジェクト変数「InpAreaV」をRangeオブジェクト変数「SortAreaD」に代入します。

VBA
Function SortAreaD() As Range
        If ErEnd = True Then Exit Function
        Set SortAreaD = InpAreaV
End Function

並び替え範囲部分指定をコード化する(変数InpAreaV)

ユーザーフォーム「ソートナビゲーター」の中の「部分範囲指定実行」ボタンが押されると、

並び替え範囲の部分指定のためのインプットボックスが表示されます。そしてマウス操作で範囲を指定します。

データエリアのデータの列幅と部分指定したデ^他の列幅が異なる場合は、警告表示があります。

並び替え範囲部分指定

インプットボックスで部分指定エリアを入力します。(マウスでの範囲指定が楽です)

「ソートナビゲーター」のテキストボックスにも範囲表示されます。

パターン④概念図のような、並び替え範囲部分指定の列幅がデータ本体の列幅と異なる場合は、

” データを壊す可能性がある” という警告を表示します。そのまま続行すれば、指定キーでその指定部分だけ並び替えが実行されることになります。

部分指定エリアが、データ全体の列幅と同じ場合は警告表示はされません。

また同時に、部分指定した並ぶ替え範囲を太い罫線で枠囲みを行い、罫線データを取得します。

VBA
Sub 並び替え範囲部分指定()
    Dim ANS As Long
        AreaVAlert = False
        Set InpAreaV = Nothing
        ソートナビゲーター.部分範囲指定表示.Value = ""
        On Error Resume Next
        Set InpAreaV = Application.InputBox("並び替え範囲を指定" & _
            "してください。", Title:="並び替え範囲指定", Type:=8)
        If Err.Number > 0 Then
            MsgBox "キャンセルされました。終了します。"
            ErEnd = True
            Exit Sub
        End If
        ソートナビゲーター.部分範囲指定表示.Value = _
            InpAreaV.Address(False, False)
        On Error GoTo 0
        With InpAreaV
            If Not (Cells(.Row, .Column).CurrentRegion.Columns.Count _
                = InpAreaV.Columns.Count And Cells(.Row, .Column) _
                .CurrentRegion.Column = InpAreaV.Column) Then
                AreaVAlert = True
                ANS = MsgBox("このまま並び替えを行うとデータを壊す" & _
                "可能性があります。" & vbCrLf & "続けますか?", _
                vbYesNo + vbQuestion, "確認")
            End If
            If ANS = 7 Then
                Exit Sub
            End If
        End With
        Set Bodu = InpAreaV.Borders(xlEdgeTop)
        Set Bodd = InpAreaV.Borders(xlEdgeBottom)
        Set Bodl = InpAreaV.Borders(xlEdgeLeft)
        Set Bodr = InpAreaV.Borders(xlEdgeRight)
        BoduL = Bodu.LineStyle
        BoduW = Bodu.Weight
        BoddL = Bodd.LineStyle
        BoddW = Bodd.Weight
        BodlL = Bodl.LineStyle
        BodlW = Bodl.Weight
        BodrL = Bodr.LineStyle
        BodrW = Bodr.Weight
        InpAreaV.BorderAround LineStyle:=xlContinuous, Weight:=xlThick
End Sub

この選択範囲パターン④で変数「AreaVAlert」がTrueの時は、「リスタート実行」機能が実行されません。

並び替え範囲部分指定の指定位置を明確にしておく

並び替え範囲部分指定を行った時、その並び替え実行中に、どこを範囲指定しているかを明確にしておくための機能です。

選択範囲の外枠を太い罫線実線で囲みます。

メモリに部分指定範囲が保存されていれば、いつでも枠囲みする前の罫線状態に復元することが出来ます。

メモリに保存(変数値がリセットや上書きされていない状態)の間の操作が必要です。

並び替え範囲部分指定で範囲枠罫線を消去する
VBA
Sub 並び替え範囲部分指定罫線消去()
        If ErEnd = True Then Exit Sub
        If InpAreaV Is Nothing Then
        MsgBox "今回は消去する罫線がないか、または、手作業での" & _
            "消去になります。"
        Exit Sub
        End If
        InpAreaV.Select
        With InpAreaV.Borders(xlEdgeTop)
            If BoduL = -4142 Then
                .LineStyle = xlLineStyleNone
            Else
                .LineStyle = BoduL
                .Weight = BoduW
            End If
        End With
        With InpAreaV.Borders(xlEdgeBottom)
            If BoddL = -4142 Then
                .LineStyle = xlLineStyleNone
            Else
                .LineStyle = BoddL
                .Weight = BoddW
            End If
        End With
        With InpAreaV.Borders(xlEdgeLeft)
            If BodlL = -4142 Then
                .LineStyle = xlLineStyleNone
            Else
                .LineStyle = BodlL
                .Weight = BodlW
            End If
        End With
        With InpAreaV.Borders(xlEdgeRight)
            If BodrL = -4142 Then
                .LineStyle = xlLineStyleNone
            Else
                .LineStyle = BodrL
                .Weight = BodrW
            End If
        End With
End Sub

範囲選択に対応したマクロコードの設計 まとめ

並び替えの範囲選択を、大きく4つの範囲選択パターンに分類しました。

この4つのパターンで、ほぼ範囲選択は対応できると思います。

複合パターンがある場合は、パターン④の応用として対応します。

選択範囲をRangeオブジェクト変数に代入する時(Setステートメントを使用する時)に、選択範囲に不正があるとエラーストップが発生します。

エラー発生の頻度的にはよく発生する方だと思います。この時にエラーを処理するコードを必ず記述しておくことが必要ですので忘れないようにしましょう。

また、並び替え範囲の部分指定で設定した範囲を分かりやすくするための罫線での範囲枠は、結構有効利用できると思います。

エクセルVBAを独習するのに参考書は欠かせません。 参考書選びは自分に合った「相棒」にできるものを選んでいきたいです。

vbastudyeyecatch2 エクセルVBAの独習でおすすめ参考書を7冊選ぶ。良書との出会いは大切です

今回の記事はここまでです。   最後までご覧いただき有難うございました。

<記事内容についての告知>VBAコードの記述記事においては、その記述には細心の注意をしたつもりですが、掲載のVBAコードは動作を保証するものではりません。 あくまでVBAの情報の一例として掲載しています。 掲載のVBAコードのご使用は、自己責任でご判断ください。 万一データ破損等の損害が発生しても当方では責任は負いません。

アンケートでポイ活しよう!!

アンケートに答えれば答えるほど ”使える” ポイントがたまります。

NTTコム サーチ

af_banner01

Dstyle web

dstyleweb_logo
dstyle_320x50-min