0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VBAでリストを自動並び替え!A列を編集したら即座にソートする方法

0
Posted at

目次

  1. はじめに
  2. イベントプロシージャとは
  3. コードの全体像
  4. A列の変更を検知する仕組み
  5. 自動ソート処理の実装
  6. 実際に動かしてみる
  7. 応用例
  8. まとめ

はじめに

リストの項目を追加するたびに、毎回ソートボタンを押すのは面倒ですよね。今回紹介するコードを使うと、A列のどこかを編集したタイミングで自動的にリスト全体を並び替えることができます。作業の手間を大幅に減らせる便利なTipsです。

イベントプロシージャとは

イベントプロシージャは、シート上で何か操作が行われたときに自動的に実行されるコードです。Worksheet_Changeは、セルの値が変更されたときに動作するイベントプロシージャの一つで、シートモジュールに記述する必要があります。

シートモジュールへのアクセス方法は以下の通りです。

  1. ソート機能を使いたいシート名を右クリック
  2. 「コードの表示」を選択
    image.png
  3. 開いたウィンドウにコードを貼り付ける

標準モジュールではなくシートモジュールに記述する点が重要なポイントです。

コードの全体像

Private Sub Worksheet_Change(ByVal Target As Range)
    
    ' A列が変更されたときのみ実行
    If Not Intersect(Target, Me.Columns("A")) Is Nothing Then
        ' 空でないセルがある範囲を昇順に並び替え
        With Me.Sort
            .SortFields.Clear
            .SortFields.Add Key:= _
                Range("A1", Range("A" & Rows.Count).End(xlUp)), _
                SortOn:=xlSortOnValues, _
                Order:=xlAscending, _
                DataOption:=xlSortNormal
            .SetRange Range("A1", Range("A" & Rows.Count).End(xlUp))
            .Header = xlNo
            .Apply
        End With
    End If

End Sub

このコードは、A列のどのセルが変更されても、A列全体のデータを昇順に自動ソートする処理を行います。

A列の変更を検知する仕組み

【Targetパラメータの役割】

Worksheet_Changeイベントには、Targetというパラメータが渡されます。これは「どのセルが変更されたか」を表すRangeオブジェクトです。

Private Sub Worksheet_Change(ByVal Target As Range)

ユーザーがA5セルを変更した場合、TargetにはA5セルの情報が入ります。複数のセルをまとめて変更した場合は、その範囲全体がTargetに格納される仕組みです。

【Intersectメソッドで列全体をチェック】

Intersectメソッドは、2つの範囲が重なっているかを判定する関数です。

If Not Intersect(Target, Me.Columns("A")) Is Nothing Then

Me.Columns("A")は、A列全体を表します。この条件式は以下のように動作します。

  • Intersect(Target, Me.Columns("A"))で、変更されたセルとA列が重なっているか確認
  • 重なっていればRangeオブジェクトが返され、重なっていなければNothingが返される
  • Is NothingNothingかどうかを判定
  • Notで条件を反転させることで、「重なっている場合」を検知

つまり、「変更されたセルがA列に含まれていたら処理を実行する」という意味になります。A1セルでもA10セルでも、A列のどこを変更しても動作する仕組みです。

Columns("A")は列全体を指すため、A1からA1048576までの全セルが対象になります。どの行を変更してもソートが実行される点が、特定セル指定との大きな違いです。

自動ソート処理の実装

【Sortオブジェクトの基本構造】

VBAでソートを実行するには、Sortオブジェクトを使用します。With文を使うことで、何度も同じオブジェクト名を書かずに済むため、コードが読みやすくなります。

With Me.Sort
    ' ソート設定をここに記述
End With

Meは、コードが書かれているシート自体を指すキーワードです。

【SortFieldsの設定】

ソートの基準となる列や順序を指定するのがSortFieldsです。

.SortFields.Clear
.SortFields.Add key:=Range("A1", Range("A" & Rows.Count).End(xlUp)), _
    SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal

SortFields.Clearで既存のソート設定をクリアしてから、Addメソッドで新しい設定を追加します。

各パラメータの意味は以下の通りです。

  • key: ソートの基準となる範囲。ここではA1セルからデータの最終行まで
  • SortOn: 何を基準にソートするか。xlSortOnValuesは値を基準にする設定
  • Order: 昇順(xlAscending)か降順(xlDescending)か
  • DataOption: 数値と文字列の扱い方。xlSortNormalは標準的な並び替え

【データの最終行を取得する方法】

Range("A" & Rows.Count).End(xlUp)

この式は、A列の最下行から上方向に検索して、最初にデータが入っているセルを見つける処理です。Rows.Countはシートの最大行数(通常は1048576)を表します。

Ctrl+↑キーを押したときと同じ動作をコードで表現していると考えると分かりやすいかもしれません。

【ソート範囲とヘッダー設定】

.SetRange Range("A1", Range("A" & Rows.Count).End(xlUp))
.Header = xlNo

SetRangeでソートを適用する範囲全体を指定します。A1セルから最終行までを対象にしています。

Header = xlNoは、1行目がヘッダー(見出し)ではないことを示す設定です。もし1行目を見出しとして固定したい場合は、xlYesに変更するとA2セル以降だけがソートされます。

【ソートの実行】

.Apply

最後にApplyメソッドを呼び出すことで、設定した内容が実際に適用されます。

実際に動かしてみる

動作確認の手順は以下の通りです。

  1. Excelで新しいブックを開く

  2. Sheet1のタブを右クリックして「コードの表示」を選択

  3. 開いたウィンドウに上記のコードを貼り付ける

  4. Excelに戻り、A列に以下のようなデータを貼りつける

    りんご
    みかん
    いちご
    バナナ
    
  5. 自動的に昇順にソートされる

A1、A2、A3、A4のどのセルを変更しても同じようにソートが実行されます。試しにA10セルに新しい項目を追加してみてください。入力後すぐに適切な位置に並び替えられることが確認できます。

B列やC列を編集してもソートは実行されません。A列以外を変更しても何も起こらないことを確認してみてください。

応用例

【定数を使って列を簡単に変更できるようにする】

コード内に直接「A」と書かれている部分(マジックナンバー)を定数として定義すると、後から変更しやすくなります。

Const TARGET_COLUMN As String = "A"

Private Sub Worksheet_Change(ByVal Target As Range)
    
    ' 指定列が変更されたときのみ実行
    If Not Intersect(Target, Me.Columns(TARGET_COLUMN)) Is Nothing Then
        With Me.Sort
            .SortFields.Clear
            .SortFields.Add Key:= _
                Range(TARGET_COLUMN & "1", Range(TARGET_COLUMN & Rows.Count).End(xlUp)), _
                SortOn:=xlSortOnValues, _
                Order:=xlAscending, _
                DataOption:=xlSortNormal
            .SetRange Range(TARGET_COLUMN & "1", Range(TARGET_COLUMN & Rows.Count).End(xlUp))
            .Header = xlNo
            .Apply
        End With
    End If

End Sub

Const TARGET_COLUMN As String = "A"という行で、対象となる列を定義しています。B列に変更したい場合は、この1行を以下のように書き換えるだけで済みます。

Const TARGET_COLUMN As String = "B"

コード内の複数箇所を修正する必要がなくなるため、メンテナンスがしやすくなります。

【ソート順も定数で管理する】

昇順・降順の切り替えも定数で管理できます。

Const TARGET_COLUMN As String = "A"
Const SORT_ORDER As Long = xlAscending

Private Sub Worksheet_Change(ByVal Target As Range)

    If Not Intersect(Target, Me.Columns(TARGET_COLUMN)) Is Nothing Then
        With Me.Sort
            .SortFields.Clear
            .SortFields.Add Key:= _
                Range(TARGET_COLUMN & "1", Range(TARGET_COLUMN & Rows.Count).End(xlUp)), _
                SortOn:=xlSortOnValues, _
                Order:=SORT_ORDER, _
                DataOption:=xlSortNormal
            .SetRange Range(TARGET_COLUMN & "1", Range(TARGET_COLUMN & Rows.Count).End(xlUp))
            .Header = xlNo
            .Apply
        End With
    End If

End Sub

降順にしたい場合は、SORT_ORDERの値をxlDescendingに変更します。

【ヘッダー設定も定数化する】

ヘッダーの有無も定数で管理すると、設定の見通しが良くなります。

Const TARGET_COLUMN As String = "A"
Const SORT_ORDER As Long = xlAscending
Const HAS_HEADER As Long = xlNo
Const START_ROW As Long = 1
    
Private Sub Worksheet_Change(ByVal Target As Range)

    If Not Intersect(Target, Me.Columns(TARGET_COLUMN)) Is Nothing Then
        With Me.Sort
            .SortFields.Clear
            .SortFields.Add Key:= _
                Range(TARGET_COLUMN & START_ROW, Range(TARGET_COLUMN & Rows.Count).End(xlUp)), _
                SortOn:=xlSortOnValues, _
                Order:=SORT_ORDER, _
                DataOption:=xlSortNormal
            .SetRange Range(TARGET_COLUMN & START_ROW, Range(TARGET_COLUMN & Rows.Count).End(xlUp))
            .Header = HAS_HEADER
            .Apply
        End With
    End If

End Sub

ヘッダー行がある場合は、HAS_HEADERxlYesに変更します。

Const HAS_HEADER As Long = xlYes

これで2行目以降がソート対象となり、1行目は固定されます。

【複数列のデータを同時にソートする】

A列を基準にして、B列やC列のデータも一緒に並び替えたい場合は、終了列の定数を追加します。

Const TARGET_COLUMN As String = "A"
Const END_COLUMN As String = "C"
Const SORT_ORDER As Long = xlAscending
Const HAS_HEADER As Long = xlNo

Private Sub Worksheet_Change(ByVal Target As Range)

    If Not Intersect(Target, Me.Columns(TARGET_COLUMN)) Is Nothing Then
        With Me.Sort
            .SortFields.Clear
            .SortFields.Add Key:= _
                Range(TARGET_COLUMN & "1", Range(TARGET_COLUMN & Rows.Count).End(xlUp)), _
                SortOn:=xlSortOnValues, _
                Order:=SORT_ORDER, _
                DataOption:=xlSortNormal
            .SetRange Range(TARGET_COLUMN & "1:" & END_COLUMN & Rows.Count)
            .Header = HAS_HEADER
            .Apply
        End With
    End If

End Sub

END_COLUMNを変更することで、ソート範囲を簡単に調整できます。例えばE列まで含めたい場合は以下のようにします。

Const END_COLUMN As String = "E"

定数を使うメリットは、コードの可読性(読みやすさ)が向上することと、設定変更時の修正漏れを防げることです。特に複数箇所で同じ値を使う場合は、定数化することをおすすめします。

まとめ

A列の変更をトリガーにした自動ソート機能を実装する方法を紹介しました。Worksheet_ChangeイベントとIntersectメソッド、Columnsプロパティを組み合わせることで、リストの更新作業を効率化できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?