和風スパゲティのレシピ

日本語でコーディングするExcelVBA

AutoFilerはどこから実行しても既存のフィルターが実行される

知らずに落ちると抜け出せなくなるVBAの落とし穴です。

  • オートフィルターが全く違う場所で実行された
  • マクロを実行するたびに実行されるフィルターが変わる

あたりにお悩みの方は、この落とし穴に落ちていないかご確認ください。

Rangeオブジェクト.AutoFilterの仕様

例えば以下のシートで以下のコードを実行してみましょう。

サンプルシート

Range("G3:J9").AutoFilter 1, "みかん"

結果はこうなります。

抽出結果

全然違う位置でフィルターがかかっていますし、
肝心のG列~J列にはフィルターが設置すらされていませんね。


タイトルの通り、既存のオートフィルターがある場合は、
AutoFilterメソッドをどのセルから実行してもそのフィルターで抽出が実行
されてしまいます。


以下のコードが「G3~J9セルにフィルターを設置するコード」になるのは、
フィルターがシート上に存在しない時だけですのでご注意ください。

Range("G3:J9").AutoFilter 1, "みかん"

 

解決策

フィルターの抽出と設置を同時にやるのは危険なため、

  1. フィルターがすでにある場合は解除
  2. フィルターを設置
  3. フィルター抽出を実行

という手順をしっかり踏みます。


具体的なコードとしては、

' フィルターがあればフィルターを解除
Worksheets("○○").AutoFilterMode = False

' フィルターを設置
Worksheets("○○").Range("G3:J9").AutoFilter

' 抽出を実行
Worksheets("○○").Cells.AutoFilter 1, "みかん"

この手順でコードを実行します。


Range.AutoFilterはトグル形式(設置と解除を交互に実行)のメソッドですが、
このような前後の状況で処理が変わるコードを使うとマクロが不安定になるため

Worksheets("○○").AutoFilterMode = False

このコードで「フィルターの解除」を明示しているのがポイントです。


このコードは解除済みであってもエラーにはなりませんので、
このコードの直後であれば確実にオートフィルターはありません。

その後にAutoFilterを実行すれば、確実に「設置」を実行できます。


あとは抽出ですが、逆にこの実行元はどのセルでも構わないため、

Worksheets("○○").Cells.AutoFilter 1, "みかん"

と、Cellsで済ませてしまってOKです。


仕様さえ知っていれば対策は簡単ですね。

なぜこの仕様なのか+追加の注意点

なんでAutoFilterがこんな仕様になっているのかというと、
AutoFilterはテーブル(ListObject)と共存することがあるからです。

テーブル機能を使えばシート上に複数のフィルターを設置でき、
それぞれのフィルターを独自に動かせます。


その仕様の下で↓こちらのコードは、

Range("G3:J9").AutoFilter 1, "みかん"
  • G3:J9にテーブルが存在すればそのフィルター
  • そうでなければシート上の通常フィルター

を取得するコードとして動きます。

このためテーブルのないシートでは結果として、
「どこから実行しても既存のフィルターが使われるコード」
になったということですね。


ここで一つ注意点なのですが、先ほど
「このコードの直後であれば確実にオートフィルターはありません。」
と説明したのは、あくまで通常フィルターしかないシートの話です。

テーブルと通常フィルターが混在したシートではそうとは限らず、
かなり複雑な指定が必要になりますのでご注意ください。


本来あまりやるべきではありませんが、
必要になりましたら以下の記事をご参照ください。
www.limecode.jp