2

我有一种情况,在某些情况下,我需要打开另一个表单并保持该表单的焦点(模态 = true),当它们不关闭并且关闭时,父表单上的控件会使用可能已更改的数据进行刷新.

最初我有一种方法可以DoEvents在子表单打开时使用,但它会导致一些子表单无法使用(它们在表单级别没有数据绑定)用于数据输入/编辑。

ShowForm 方法 - 最初

Public Sub ShowForm(par As Form, nm As String, _
                    Optional whr As String = "", _
                    Optional args As String = "", _
                    Optional mode As AcFormOpenDataMode = acFormPropertySettings)
    DoCmd.OpenForm nm, acNormal, , whr, mode, , args
    
    While IsOpen(nm)
        DoEvents
    Wend
End Sub

为了让子表单始终可用,我不得不注释掉While...Wend循环。

我是否可以在此方法或调用控件的 OnClick 中使用另一种逻辑模式,这样当他们关闭子窗体时,我可以在子窗体关闭后执行代码?

4

4 回答 4

3

最简单的方法是简单地以对话模式打开表单。例如,

DoCmd.OpenForm nm, acNormal, , whr, mode, acDialog, args

这将暂停调用模块中代码的执行,直到表单关闭。它还将阻止用户与任何其他表单交互,直到“对话框”表单关闭。


我发现在对话框模式下打开绑定表单,更新数据,关闭表单,然后刷新调用表单上的对象(例如,组合框的行源)并不总是可靠的。

下面是我编写的一个通用函数,用于“暂停”调用代码,而无需在对话框模式下打开表单,也不会显着影响用户界面的性能。它适用于表单和报告。请注意,睡眠 API 声明必须位于代码模块的顶部(在模块声明部分)。

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'-------------------------------------------------------------------------------
' Procedure : WaitTilObjClosed
' Author    : Mike
' Date      : 1/7/2009
' Purpose   : Halts program execution until user closes object.  User is 
'               generally unaffected by the loop.
' Requires  : Sleep API sub
' Notes - while Sleeping other programs can use processor but access cannot;
'       - during DoEvents, other parts of Access can use processor;
'       - without the Sleep call, processor usage stays at 100% for MSACCESS.EXE
'       - with a long Sleep call, Access becomes noticeably sluggish
'-------------------------------------------------------------------------------
'
Sub WaitTilObjClosed(ObjType As AcObjectType, ObjName As String)
    Do
        DoEvents
        Sleep 1
        If (SysCmd(acSysCmdGetObjectState, ObjType, ObjName) = 0) Then Exit Do
    Loop
End Sub

您可以按如下方式使用它:

DoCmd.OpenForm "MyForm"
WaitTilObjClosed acForm, "MyForm"
MsgBox "MyForm is now closed"

DoCmd.OpenReport "MyReport", acViewPreview
WaitTilObjClosed acReport, "MyReport"
MsgBox "MyReport is now closed"
于 2012-09-06T17:57:41.227 回答
0

我想我现在明白你的问题了。不幸的是,没有简单的方法可以做你想做的事。我建议使用以下算法:

'Grandparent/parent form module
Dim ChildForm As String

Private Sub ShowFormBtn_Click()
    DoCmd.OpenForm "MyForm"
    ChildForm = "MyForm"
End Sub    

Private Sub ShowOtherFormBtn_Click()
    DoCmd.OpenForm "OtherForm"
    ChildForm = "OtherForm"
End Sub

Private Sub Form_Activate()
    On Error Resume Next
    Forms(ChildForm).SetFocus
End Sub

Private Sub Form_Unload(Cancel As Integer)
    On Error Resume Next
    Forms(ChildForm).SetFocus
    If Err.Number = 0 Then Cancel = True
End Sub

基本上,每次您尝试切换到父表单时,它都会尝试将用户发送到其子表单(如果存在)。如果它没有子节点,则会生成一个被静默忽略的错误。如果孩子确实存在,它会将其切换到该表单。

这也支持多个级别。因此,假设您有一个祖父表单,该表单生成一个父表单,该父表单生成一个子表单。这三种形式都是开放的。您单击将焦点发送到父窗体的祖父窗体,父窗体将焦点发送到子窗体。

于 2012-09-06T18:53:23.270 回答
0

您不想锁定FORM本身,您想锁定属于FORM. 下面解释了我进行控制锁定的首选方法。目标是使每个用户可编辑的控件都是只读的

在您父级的 VBA 代码中FORM创建此子:

public sub LockControls_[Enter Form Name Here]()

  ME.txt1.Locked = True
  ME.txt2.Locked = True
  ME.txt3.Locked = True
...

end sub

您可以锁定文本框、组合框、按钮等...

如果您的控件遵循我上面概述的命名结构,您实际上可以通过执行以下操作来循环它:

public sub LockControls_[Enter Form Name Here]()

  Dim s_ctrl As String
  Dim s_obj As String
  Dim i as Int

  i = 0
  s_ctrl = "txt"
  s_obj = s_ctrl & i

  do while me(s_obj).Name <> ""

      Me(s_obj).Locked = True
      i = i+1
      s_obj = s_ctrl & i

  loop
end sub

从启动子表单的操作中调用此方法。它将锁定(只读)表单上的所有控件,同时让用户可以访问表单。

FORM当从子窗体上的关闭事件调用时,可以使用相同的方法来解锁您的父级。请务必不要使用Me(s_obj).Locked = False. 相反,使用以下语法完全限定您的表单:

public sub UnLockControls_[Enter Parent Form Name Here]()

  Dim s_ctrl As String
  Dim s_obj As String
  Dim i as Int

  i = 0
  s_ctrl = "txt"
  s_obj = s_ctrl & i

  do while me(s_obj).Name <> ""

      FORMS![form_name](s_obj).Locked = False
      i = i+1
      s_obj = s_ctrl & i

  loop
end sub
于 2012-09-06T19:11:09.323 回答
0

这是我最初的问题中该方法的最终形式:按我的意愿工作(现在;)),感谢@Remou 和@mwolfe02。

最终形式 - 当然是临时的

'@frm - String value, Name of the form to Open
Public Sub OpenForm(frm As String, _
                    Optional vw As AcFormView = acNormal, _
                    Optional whr As String = "", _
                    Optional mode As AcFormOpenDataMode = acFormPropertySettings, _
                    Optional args As String = "")
    If FormExists(frm) Then
        DoCmd.OpenForm frm, vw, , whr, mode, acDialog, args
    Else
        RaiseError "Form ( " & frm & " ) does not exist!" & vbCrLf & vbCrLf & _
                    "Alert your IT Support for further assistance."
    End If
End Sub
于 2012-09-06T19:28:10.387 回答