#07 開いているオブジェクトを一括クローズ

ここでは「#06 開いているオブジェクトの一覧を取得する」の応用として、開いているオブジェクトを一度にまとめて閉じてみます。
 
AccessでVBAを使って開発をしていると、時としてすべてのコードに対して検索や置換を行うことがあります。そしてその対象となる文字列が見つかると、モジュールウィンドウが開かれて、その文字列の部分で検索や置換が一時停止します。ところがその対象となるモジュールウィンドウがたくさん開かれると後が大変です。特にフォームやレポートではモジュールだけでなく、デザインウィンドウまでも開かれてしまいます。そのような時のために作ったのがT'sKitの「オブジェクト一括クローズ」ツールです。しかしその中味は「#06 開いているオブジェクトの一覧を取得する」の内容が解ればいたって簡単です。各プロパティを取得する部分をオブジェクトを閉じるコードに書き換えればいいだけです。
つまり、 

  Dim iintLoop As Integer
 
  For iintLoop = 0 To Forms.Count - 1
    DoCmd.Close acForm, _
                Forms(iintLoop).Name右上へ
  Next iintLoop

のようにすればいいのです。

ところが、実はこのままではエラーとなってしまいます。なぜなら、1つフォームを閉じるたびに[Forms]コレクションに含まれるフォームの数が減っていってしまうからです。例えば下の図のようにあらかじめ フォーム1〜フォーム4 の4つのフォームが開いているとします。

まず最初に iintLoop = 0 で Forms(0) の"フォーム1"がクローズされると、Forms(1)〜Forms(3)は1つずつ前へシフトします。For〜Nextでは次に iintLoop = 1 で Forms(1) をクローズしますので、実際には"フォーム3"が閉じられ"フォーム4"が前へシフトしてきます。この時点で Forms(2) のフォームはなくなるので、iintLoop=2 で実行時エラーとなってしまうのです。
Forms(0)を削除する図 右矢印Forms(1)を削除する図右矢印Forms(2)を削除する図

そこでこのことを考慮してコードを修正してみます。ここでは要するに後ろからクローズしていくわけです。

  Dim iintLoop As Integer
 
  For iintLoop = Forms.Count - 1 To 0 Step -1
    DoCmd.Close acForm, _
                Forms(iintLoop).Name
  Next iintLoop

この動作を図示すると下のようになります。

なお、For iintLoop = Forms.Count - 1..... というステートメントで、Forms.Count の値もクローズによって減っていくわけですから何か問題がありそうですが、ステップ実行してみれば分かるのですが、このステートメントは最初に1回実行されるだけなので、Forms.Count の実体の値が変ってしまってもループの上限値としては最初の値が保持されてうまく動作します。
Forms(3)を削除する図 右矢印Forms(2)を削除する図右矢印Forms(1)を削除する図
ころで、T'sKitの「オブジェクト一括クローズ」ツールではオブジェクトの閉じ方として3つの方法を選択できるようになっています。

「確認して閉じる」、「すべて保存して閉じる」、「すべて保存せずに閉じる」の3つです。「確認して閉じる」は、もしそのオブジェクトのデザインが変更されている場合に保存するかどうかのメッセージを表示します。他の2つは変更の有無に関わらず、強制的にそれぞれ保存・破棄します。これらの選択は、データベースアプリケーションの中で DoCmd.Close を使う場合には通常必要ないと思いますが、T'sKitのようなアドインツールでは重要となってくるでしょう。これらは DoCmd.Close メソッドのパラメータを指定することによって切り替えることができます。

オブジェクト一括クローズの画面イメージ
確認して閉じる DoCmd.Close acForm, Forms(iintLoop).Name, acSavePrompt
すべて保存して閉じる DoCmd.Close acForm, Forms(iintLoop).Name, acSaveYes
すべて保存せずに閉じる DoCmd.Close acForm, Forms(iintLoop).Name, acSaveNo
後に、「#06 開いているオブジェクトの一覧を取得する」ではその方法として2つの考え方を挙げましたが、閉じる場合にも同様のことが言えると思います。開いているオブジェクトについて1つずつ閉じる方法(今回説明した方法)とデータベースに保存されているすべてのオブジェクトを閉じていく方法です。
ただし閉じる場合にはいちいちそのオブジェクトが開いているかどうかを確認する必要はありません。DoCmd.Close を実行した際、そのオブジェクトが開いていなくてもエラーは発生しないからです。あらかじめ、開いている可能性があるオブジェクトがすべて分かっているようなケースではこちらの方法が手っ取り早いかもしれません。状況に応じて使い分けてみて下さい。
| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved