いつもお世話になっております。
今現在、ACCESSのフォームとして、起動時に開く『F_メイン』と、
情報の編集・閲覧を行う『F_部品』『F_製品』があります。
メインフォームの終了ボタンクリック時に以下のように、2つのフォームが変更されているか
どうかを確認する処理を入れています。
Private Sub 終了ボタン_Click()
DoCmd.OpenForm "F_部品"
If Forms!F_部品.Dirty Then
MsgBox "[部品フォーム] が変更されています。" & Chr(13) _
& "データの変更を保存してください。", vbOKOnly + vbCritical, "エラー! 終了できません"
Exit Sub
Else
DoCmd.Close acForm, "F_部品"
End If
DoCmd.OpenForm "F_製品"
If Forms!F_製品.Dirty Then
MsgBox "[製品フォーム] が変更されています。" & Chr(13) _
& "データの変更を保存してください。", vbOKOnly + vbCritical, "エラー! 終了できません"
Exit Sub
Else
DoCmd.Close acForm, "F_製品"
End If
DoCmd.Quit acQuitPrompt
End Sub
これで、うっかりデータを変更しちゃってフォームを閉じちゃった際にも、
データ変更云々のメッセージを表示できるようになりました。
しかし、部品フォーム・製品フォームの読み込み時イベントに、下記のような
UseLog を Call Uselog("●●","△△") で呼び出しており、
メインフォームを閉じる際に(上記で部品フォームとかを開くので)それが働いてしまいます。
Public Sub UserLog(ByVal PlaceName As String, ByVal ActionName As String)
Dim DB As DAO.Database: Set DB = CurrentDb
Dim WSH As Object: Set WSH = CreateObject("WScript.Network")
Dim PN As String: PN = PlaceName
Dim AN As String: AN = ActionName
DB.Execute "insert into T_UserLog (Place,Action,UserN,MachineN) values('" & PN _
& "','" & AN & "','" & WSH.UserName & "','" & WSH.ComputerName & "')"
これにより、ユーザログ蓄積テーブルに、部品フォームを開いた旨等が記録されてしまいます。
(しかも何故か部品フォームの方だけ毎回、どちらかを変更しているとどちらも記録)
このUserLogを働かせずに、かつ、閉じてしまったフォームの変更の是非を問えるようにするには
どうしたらよいのでしょうか?
稚拙な質問ではございますがよろしくお願い致します。
また、VBAに問題や改善点などありましたら、そこもお教え下さると幸甚に存じます。
そもそも、これが勘違いではないでしょうか。
フォームを閉じる時に、もしレコードが更新されていたら、自動的に保存されて、Dirtyプロパティはリセットされます。
DoCmd.OpenForm "F_部品" で開いた直後、DirtyプロパティはFalseになっているはずです。
もし、「データ変更云々のメッセージを表示」のメッセージが出るなら、フォームを開く時、読み込み時、レコード移動時、、などで、レコードを更新する処理が記述されていることになります。
お早いご返信、ありがとうございます。
前に1度、部品フォームを変えてから閉じて、メインフォームを閉じようとしたら閉じれなかった
と他の人から連絡を受けたため、このような形になっていました。
しかし、考えてみると、確かにご指摘通りへんてこりんですね…。
申し訳ありません。
MSGBOXの出現も、いろいろ試したところ、フォーム開きっぱなしの時だけでした。
部品フォームを閉じるときに、以下のようにすれば問題ないでしょうか…?
以上、よろしくお願いいたします。
よくわからないんですが、編集(変更)したのに保存したくない場合があるんですか?
データの保存(する/しない)と、フォームを閉じるは、直接的には無関係です。変更中の内容をどうこうしたいなら更新前処理で制御すべきでしょう
ありがとうございます。
都合により、データの閲覧と編集を同じフォームで行っています。
(フォームを分けるという理解を得られていない為、これは変更できなさそうです)
データ編集ユーザ用に、保存ボタンや編集クリアボタン等を配置しています。
しかし、データを見るだけのつもりのユーザーが誤って一部のデータを変更し、
それに気が付かぬまま(=編集クリアボタン等を押さぬまま)フォームを
閉じようとする際(およびレコード移動する際)に、MSGBOXで警告するようにしています。
フォームはマスタテーブルをレコードソースとしており、フォーム内の
TXTBOXを変更した際に、すぐテーブル内容が書き換わってしまわないように、
としています。
根本的にデータ更新タイミングなどが間違っているということでしょうか…
とりあえず
フォームの状態を知るには?(T'sWareさん)
質問のコードを次のように変更すれば動作はすると思います
フォームが開いているかどうかをチェックし、開いているときに限りDirtyプロパティをチェックすれば良いということですね
データの更新自体は様々なタイミングで発生します。フォームを閉じるというアクションを取った場合は、Closeイベントの前にBeforeUpdateイベントが発生し、BeforeUpdateイベントが終わると保存内容が決定されます
(実際にはもっと様々なイベントが発生します)
イベントは1つのアクションに対して連鎖的に複数発生する場合があるので、どのイベントで処理するか適切に判断する必要があります
Closeイベントの時点ではすでにデータが決定されてしまっているので、そこで保存するかどうかの確認や、再度データを変更・保存しなおすような処理はすべきではありません
「データの更新処理が済んでないうちはフォームを閉じる処理をしてはいけない」という意味で、修正しようとした内容よりも質問時点でのコードのほうが考え方が正しいです
毎度、手取り足取り本当にありがたいです。
Dirtyは、開いてないと使えないヨ、くらいしか知識が無かったので
Syscmdも有効活用していきたいと思います!
ありがとうございます…!
まだまだイベントのタイミングがうまくつかめていないので、
その部分についてももう一度勉強しなおしてみようと思います。
また、部品フォームのDirty部分なんですが、以下のような形にしました。
メインフォームの方はこのように
SysCmdを用いた、hirotonさんの方法でなく、上記のようなものでも
今回の件については問題なく動きますでしょうか?
理想の運用ならそれでいいと思いますが、フォームって予期せぬ閉じ方をされるんですよね
フォーム右上の×をクリックされたり(非表示にできるので何とかなる)、ACCESS本体の右上の×をクリックされたり(本体の表示をしない方法があるので何とかなる)、タスクバーから終了されたり、タスクマネージャーから強制終了されたり・・・
なので、実際にデータが決定されるタイミング(BeforeUpdate)で内容を決めましょう。という話です
こうしておけば、どのような形でフォームが閉じられてもBeforeUpdateイベントを通るので保存内容の確認ができます
ちなみに、>> 5が微妙な書き方なのは、このような処理を考えるとドツボにはまるからです。(本当にやりたいことは別なのに)
BeforeUpdate
でCancel = True
したいがためだけに閉じるときに更新前処理をキャンセルすると出るメッセージを変更(hatena chipsさん)
こんな処理考えるくらいなら
これの要求を整理して、メニューに編集用、閲覧用2つボタン置く形じゃダメなの?とかの方向性を考えたほうがよっぽど建設的です
ありがとうございます。
とりあえず、通常通りの操作であれば問題なく動くようにした状態まで
もっていってから、フォームを分ける用に変えていきたいと思います。
(本格的に変えていくのは新年からとなると思いますが)
フォームの更新前処理の条件式や、フォーム構成なども見直す方向で
考えていきたいと思います。
本当にありがとうございます!