- 締切済み
Accessでサブフォームの合計をメインフォームに
Access2007で開発しています。 メインフォームにサブフォームを貼り付けており、 サブフォームに入力した「数量」「単価」から「金額」を計算して表示し、 その合計金額をメインフォームのテキストボックス(非連結)に表示しようと しています。 サブフォームは行単位で追加、削除が可能です。 サブフォームの更新結果が正しくメインフォームに表示されずに困っています。 おわかりの方、おられましたらお教え頂きたく、よろしくお願い致します。 【サブフォーム】 ・レコードソース:T_明細 ・[詳細]項目:数量・・・レコードソース=T_明細・数量 単価・・・ 〃 =T_明細・単価 金額・・・数量および単価のAfterUpdateで計算して表示。 [フォームフッター]項目:金額計・・・コントロールソース=Sum([金額]) ・Vbaコード: Private Sub Form_AfterUpdate() Forms![メインフォーム].合計計算 End Sub Private Sub Form_Delete(Cancel As Integer) Forms![メインフォーム].合計計算 End Sub 【メインフォーム】 ・テキストボックス:「合計金額」(非連結) Public Sub 合計計算() Me.サブフォーム.Requery 方法1: Me!合計金額 =DSum("金額", "T_明細", (キー項目指定 記述省略)) 方法2: Me!合計金額 = Me![サブフォーム].[Form].[金額計] End Sub ここで、 方法1の場合:数量、単価の変更入力及び行追加は正しく動作するが、 行削除の後、メインフォームの「合計金額」が再計算されず、変更前のまま。 方法2の場合:数量、単価の変更入力及び行追加すると、「合計金額」が”0”になる。 行削除しても「合計金額」は変わらず、変更前のまま。 どちらも、サブフォオームの「金額計」は正しく表示されています。 以上、よろしくお願い致します。
- みんなの回答 (7)
- 専門家の回答
みんなの回答
- 30246kiku
- ベストアンサー率73% (370/504)
#6です > ご提案頂いた方法を試してみますね とのことなので、#5での注意点を。 サブフォームは帳票フォームで、レコードセレクタを使って、 「Delete」キーでレコードを削除する操作が前提になっています。 また、レコードセレクタで行を選択する際、「新規行は含まれない」ことが前提です。 新規行を含んだ選択された場合、記述を変更する必要があります。 それ用のコードも用意してましたが、必要であれば提示できます。 ※ でも、Form_Delete 以降が呼ばれないのは不思議ですね。
- 30246kiku
- ベストアンサー率73% (370/504)
#5です 記述の訂正を (時間が取れない場合は、放置してください) > ちなみに、 > Me.サブフォーム.Requery > を > Me.サブフォーム.From.Requery ★ ★部分 From ではなく Form でした Me.サブフォーム.Form.Requery
お礼
わざわざロジックを考えて下さいまして、ありがとうございます! 気づくのが遅くなりました。申し訳ありません。 ご提案頂いた方法を試してみますね。ただ、今は納期が迫っており、時間がとれませんので、もう少々お待ち下さい。 重ねて、ありがとうございました。
- 30246kiku
- ベストアンサー率73% (370/504)
#3です 解決された様でなによりです。 土日もがいていて、それなりに推測した結果のものになります。 お手数ですが、推測があっているかどうかだけでも教えていただけないでしょうか。 サブフォームは、帳票であることが前提となっています。 > (なお、今回の質問では単純化していますが、実際は、複雑な処理も行うため、またユーザインファーフェースのことも考慮して、VBAで作成しています。) と言う事なので、キー操作等統一する為に「クラス」を作って、そこで共通の処理を記述していないでしょうか。 また、親の関数先頭で行っている Me.サブフォーム.Requery は、行を移動しないで Requery したかったのでしょうか。 ちなみに、 Me.サブフォーム.Requery を Me.サブフォーム.From.Requery に変更すると、「3246の この操作は、トランザクションには実行できません」 のエラーになったと思います。(削除の処理中なので) クラスを作って、Form_Delete 時に自力削除(以降のイベントは起きない)例を以下 クラス「clsFrm」を新規挿入し、以下を記述します。 Option Compare Database Option Explicit Private Const EVENT_PROCEDURE As String = "[EVENT PROCEDURE]" Private WithEvents frm As Form Private iCount As Long Private bDel As Boolean Private Sub Class_Initialize() Set frm = CodeContextObject frm.OnDelete = EVENT_PROCEDURE iCount = -1 bDel = False End Sub Private Sub Class_Terminate() Set frm = Nothing End Sub Private Sub frm_Delete(Cancel As Integer) Dim i As Long DoCmd.CancelEvent If (frm.SelHeight < 1) Then Exit Sub If (iCount < 1) Then iCount = frm.SelHeight If (iCount = frm.SelHeight) Then bDel = MsgBox(frm.SelHeight & "件 削除しますか?" _ , vbQuestion + vbYesNo, "確認") = vbYes End If iCount = iCount - 1 If (iCount = 0) Then If (bDel) Then With frm.Recordset For i = 1 To frm.SelHeight .Delete .MoveNext Next End With frm.SelHeight = 0 End If bDel = False End If End Sub サブフォームに以下を記述します。 Dim frm As clsFrm ' ★ Private Sub Form_AfterDelConfirm(Status As Integer) MsgBox "Form_AfterDelConfirm" End Sub Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer) MsgBox "Form_BeforeDelConfirm" End Sub Private Sub Form_Delete(Cancel As Integer) MsgBox "Form_Delete" Call Me.Parent.Req End Sub Private Sub Form_Load() Set frm = New clsFrm ' ★ End Sub Private Sub Form_Close() Set frm = Nothing ' ★ End Sub ★部分がクラスを使う宣言みたいなもの メインフォームに以下を記述します。 Public Sub Req() Me.FSUB.Requery ' 方法1 End Sub ※ FSUB はサブフォームコントロール名 この記述で Form_Delete しか呼ばれないものは作れました。 (細かいタイミングまではみてません。動いたっぽいレベル) (サブフォーム Form_Delete の Cancel は意味を持たなくなります) このようになっていると、Form_Delete のタイミングは使えないので、 クラスに制御を渡さないで、 サブフォームで「キーイベント取得」を「はい」として、例えば、 Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) Dim i As Long Select Case KeyCode Case vbKeyDelete If (Me.SelHeight < 1) Then Exit Sub KeyCode = 0 If (MsgBox(Me.SelHeight & "件 削除しますか?" _ , vbQuestion + vbYesNo, "確認") = vbYes) Then With Me.Recordset For i = 1 To Me.SelHeight .Delete .MoveNext Next End With Me.SelHeight = 0 Call 親の関数 End If End Select End Sub とすればやりたいことはできそうです。 (この場合 Form_Delete は呼ばれません) 親の関数では、方法1の方が良さそうです。 ただ、処理を統一したいクラスを使わなくなるので、良いのか悪いのか。 クラス内では、キーイベント取得はやってないような気が(私の知識不足かも) なぜなら、Form_Delete は Private で呼ばれているので、 クラスから Private を呼び出せなかったような・・・ 以上、よろしくお願いいたします。
- o_chi_chi
- ベストアンサー率45% (131/287)
間違ってメインフォームに記述しているとか。。。。
お礼
回答ありがとうございます。 なるほど、ありそうですね。でもそれはありません。
補足
解決しました。 Form_Deleteイベントは、 「レコードが実際に削除される前に発生するもので、この時点ではまだ削除はされていません。」 ということなので、Form_Deleteで、(サブフォームの合計金額-削除しようとしている行の金額)を計算して、メインフォームに表示する方法で解決しました。 いろいろ考えて下さってありがとうございました。
- 30246kiku
- ベストアンサー率73% (370/504)
#1です タイミング的には #2 さんの通りだと思います。 提示した参照先の画像にあるフォームに MsgBox を組み込んでみたところ、 言われているような結果にはならず、順に呼ばれました。 私はお手上げです。 簡単なメイン/サブ構成のフォームを作成し、各イベントで MsgBox のみを記述され、 確認されてはいかがでしょうか。 失礼しました。
お礼
再度の回答、ありがとうございます。 そうですね、一度やってみます。
補足
解決しました。 教えて頂いたことがヒントになりました。 おっしゃる通りForm_Deleteイベントは、 「レコードが実際に削除される前に発生するもので、この時点ではまだ削除はされていません。」 ということなので、Form_Deleteで、(サブフォームの合計金額-削除しようとしている行の金額)を計算して、メインフォームに表示する方法で解決しました。 いろいろ考えて下さってありがとうございました。
- o_chi_chi
- ベストアンサー率45% (131/287)
このイベントで確認したらどうでしょう。 --- Private Sub Form_AfterDelConfirm(Status As Integer) If (Status = acDeleteOK) Then Forms![メインフォーム].合計計算 End If End Sub
お礼
早速回答いただき、ありがとうございます。 実は、いろいろ試行錯誤をしていまして、下記のロジックの場合、 Private Sub Form_AfterUpdate() MsgBox "Form_AfterUpdate" Forms![メインフォーム].合計計算 End Sub Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer) MsgBox "Form_BeforeDelConfirm" End Sub Private Sub Form_Delete(Cancel As Integer) MsgBox "Form_Delete" End Sub Private Sub Form_AfterDelConfirm(Status As Integer) MsgBox "Form_AfterDelConfirm" If (Status = acDeleteOK) Then Forms![メインフォーム].合計計算 End If End Sub 表示されるMsgboxは、"Form_Delete"のみでした。 他のイベントが発生しない理由がわからず、困っています。 他の案があれば、どうかご提案下さい。
- 30246kiku
- ベストアンサー率73% (370/504)
VBA は必要無いような気がします。 過去 QA で、解決されていませんが近い構成だと思います。 access2010のフォーム上で計算したいです http://okwave.jp/qa/q7079470.html VBA でやる場合、イベントの発生タイミングを確認されたらと思います。 削除の操作を行うと、 Form_Delete / (Form_Current) / Form_BeforeDelConfirm / Form_AfterDelConfirm のイベントが順に発生したと思います。 何もしないと、「削除しますか?」のAccessからのメッセージは、 Form_BeforeDelConfirm 後に表示されたと思います。 なので、Form_Delete 時に合計金額を求めても元のままだと思います。
お礼
早速回答いただき、ありがとうございます。 Form_BeforeDelConfirm、Form_Delete、Form_AfterDelConfirm のそれぞれに Msgbox をつけて実行したところ、 行削除をしたタイミングで発生するイベントは Form_Delete のみでした。 ここで合計金額を求められないとすれば、タイミングがないですよね。 行削除を、別の方法で行うしかないのでしょうか。 他の提案があれば、ご教示いただきたく、よろしくお願いします。 (なお、今回の質問では単純化していますが、実際は、複雑な処理も行うため、またユーザインファーフェースのことも考慮して、VBAで作成しています。)
お礼
大変お返事が遅くなり申し訳ありません。 お教え頂いた方法、クラスを作るやりかたおよび、「キーイベント取得」を”はい”にする方法とやってみました。 どちらも、サブフォームの行削除は正常にできるのですが、親フォームの合計金額は変わりませんでした。(親フォームの合計計算モジュールは、実行されます。) いろいろご指導いただき、本当にありがとうございました。