查找打开的子窗体



我有一个子窗体,它有一个打开另一个窗体的按钮。
在辅助窗体上,用户可以选择地址
所选地址应应用于呼叫表单。

我在打开子窗体时传递了窗口句柄。
但当它试图在Forms集合中找到调用窗体时,它不在那里
我怀疑这是因为调用表单实际上是一个子表单
我不知道从这里到哪里去。

调用表单,传递窗口句柄

OpenCCCustAddr [CustFID], "CCInt", Me.hWnd

在Form Close事件中,我尝试在调用表单上设置地址值,但是GetFormByHWND返回null。

Set frm = GetFormByHWND(Me!txtCallingHWND)
// Me!txtCallingHWND here is populated and looks reasonable
frm!BillStreet = strAddr  // This blows up since frm is null
frm!HolderZipCode = strZip
frm!AddressUpdated = -1
Set frm = Nothing

Public Function GetFormByHWND(lngHWND As Long) As Form
Dim frm As Form
Dim nm As String
Select Case lngHWND
Case 0
Case Else
For Each frm In Forms
nm = frm.NAME   // the name of the parent form shows, but not my calling subform
If frm.hWnd = lngHWND Then
Set GetFormByHWND = frm
Exit For
End If
Next
End Select
End Function

For Each和For I=0 to Count-1都给出了相同的结果。表单不在表单中。这可能是因为它是一个子表单。

我尝试搜索子表单,但当我用";对象不支持此属性";

Public Function GetFormByHWND(lngHWND As Long) As Form
Dim frm As Form
Dim ctl As Access.Control
Dim nm As String

Select Case lngHWND
Case 0
Case Else
For Each frm In Forms
nm = frm.NAME
If frm.hWnd = lngHWND Then
Set GetFormByHWND = frm
Exit For
End If
Next
Rem If we didn't find the form, check for a subform
If GetFormByHWND Is Nothing Then
For Each frm In Forms
nm = frm.NAME
For Each ctl In frm.Controls
If ctl.Properties("ControlType") = acSubform Then
nm = ctl.NAME
If ctl.hWnd = lngHWND Then  // Error: "Object doesn't support this property" 
Set GetFormByHWND = ctl
Exit For
End If
End If
Next
Next
End If
End Select
End Function

正如@June7所指出的,我的错误是假设控件窗体。相反,一个窗体。

因此,正确的解决方案是

Rem If we didn't find the form, check for a subform
If GetFormByHWND Is Nothing Then
For Each frm In Forms
For Each ctl In frm.Controls
If ctl.Properties("ControlType") = acSubform Then
If ctl.Form.hWnd = lngHWND Then // note the change here
Set GetFormByHWND = ctl.Form
Exit For
End If
End If
Next
Next
End If

首先,不清楚为什么需要所有这些代码和硬件?

我们假设你有一张表格。

在这个表单上,你有一个按钮,它会启动第二个表单。

因此,在第一种形式中,我们有这个:

' write data to table before launching form
If Me.Dirty = True Then Me.Dirty = False

DoCmd.OpenForm "formB"

好的,现在在formB加载事件中,我们有这个:

Option Compare Database
Option Explicit

Dim frmPrevious      As Form
Dim frmPreviousSub   As Form

Private Sub Form_Load()

Set frmPrevious = Screen.ActiveForm

Set frmPreviousSub = frmPrevious.MySubFormControl.Form


' do whatever

End Sub

所以现在我们既参考了上一个表格,也参考了子表格

假设用户选择了某个地址并点击ok按钮。

然后代码执行以下操作:

frmPreviousSub!AddressID = me!ID    ' get/set the PK address ID
docmd.Close acForm, me.name

因此,不需要世界上所有的贫困,抓取和循环hwnd或任何这样的手。

只有几行干净漂亮的代码。

现在,我有一个递归循环,它将始终作为对象引用返回表单句柄,因此您甚至不必对表单名称进行硬编码。

假设主表单有2个子表单,在这些子表单上,你有

公司地址和收货地址。因此,你想从这两个子表单中的任何一个启动表单B,当你选择一个地址时,你会返回该值,因此两个甚至潜在的3个子表单实际上可以通过这种方式调用弹出地址选择器表单

你这样做的方式类似于上面的代码,但我们不需要硬编码子表单。

代码现在看起来是这样的:

Private Sub Form_Load()

Dim f       As Form
Set f = Screen.ActiveForm     ' pick this up RIGHT away - 
' previous active form only valid
' in open/load event

' we have the previous active form, get the sub form.

Set frmPrevous = GetSubForm(f)

End Sub

注意,该子形式可以是3级甚至5级深。这个程序是";递归";。它获取上一个表单,然后检查子表单是否有焦点。如果子窗体有焦点,那么它就得到了控制,如果控制是一个子窗体,那么它就会一直持续下去,直到我们钻下这个兔子洞,再也不会钻下去了。

这个例程应该放在表单之外,并放在您的标准";全局";例程模块。

Public Function GetSubForm(f As Form) As Form

Static fs         As Form

If f.ActiveControl.Controltype = acSubform Then
GetSubForm f.ActiveControl.Form
Else
Set fs = f
End If

Set GetSubForm = fs

End Function

请注意,如果它发现一个子窗体具有焦点,该怎么办?好吧,然后它就用那个形式再次自称,并继续往下钻。因此,无论形式是1级还是5级都无关紧要。得到的";frmPrevious";将是对该子表单的有效引用,因此在您选择或在假定的弹出表单中执行某些操作之后?你可以设置一些PK或其他什么的值,然后关闭表单。

没有hwnd,非常干净的代码,递归技巧意味着,即使对于超过一个深度的嵌套子表单,您的frmPrevious实际上也是对启动我们弹出的表单的表单的引用,供用户选择。

如果您没有通用的"地址ID"列?然后我们的弹出表单应该假设您总是在调用表单中定义了一个公共变量

将ReturnAddressID称为长

确保你在公开时淡化了价值,比如这样说:

Public ReturnAddressID as long

所以,现在在我们的弹出表单中,我们可以这样做:

frmPrevious.ReturnAddressID = me!PD
frmPrevous.MyUpdate

(我们假设所有调用弹出窗口的表单都有一个名为MyUpdate.的公共函数

因此,现在我们有了一种通用的方法,以及2到10种不同的地址形式,即使子形式现在可以调用一个地址选择器。只要这些表单中的任何一个采用了公共ReturnAddressID和公共函数MyUpdate,那么我们就可以传递回这些值,MyUpdate就会将ReturnAddressID推送到/获取/设置到您在该子表单中为地址ID使用的任何列和值中。

当然,如果没有子表单,例程将只返回称为弹出表单的最顶部表单。

最新更新