将CallByName与“事件接收器"一起用于表单上的字段 [英] Using CallByName with an 'event sink' for a field on a form

查看:61
本文介绍了将CallByName与“事件接收器"一起用于表单上的字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在应用程序中的几种表单上都有文本框,这些文本框具有缩放"功能-双击它们,然后会出现一个弹出表单,您可以调整其大小并编辑为您的内容.这是通过类模块"appZoomText"进行编码的,该模块充当文本框事件的事件接收器".

I have text boxes on several forms in my application that have a "zoom" capability -- double-click on them and a pop-up form appears which you can resize and edit to your hearts content. This is coded via a class module "appZoomText" which acts as an 'event sink' for the text box events.

我正在尝试创建一个内容菜单和功能区项目,以复制双击行为(对于那些不阅读文档但可能会想知道如果缩放图标会起作用的用户).

I'm trying to create a content menu and ribbon item which replicates the double click behaviour (for those of my users who don't read documentation but might wonder what a zoom icon does if they see it.)

在输入可缩放文本框时,将执行以下代码:

On entry to a zoomable text box, this code is executed:

dim mclsZoomtext as appZoomtext
set mclsZoomtext = new appZoomtext
Set mclsZoomText.pTextBox = ActiveControl

在类模块中,以下代码在Set pTextBox中执行

In the class module, the following code is executed in Set pTextBox

Private WithEvents myTextBox As Access.TextBox
Set myTextBox = pTextBox
myTextBox.OnDblClick = "[Event Procedure]"

myTextBox的双击代码为:

The double-click code for myTextBox is:

Private Sub myTextBox_DblClick(intCancel As Integer)
   OpenZoomForm 'Opens the relevant form with the right contents -- works fine
End Sub

在Set ptextBox中启用了相关菜单项,并在退出pTextBox时禁用了该菜单项(工作正常).

The relevant menu item is enabled in Set ptextBox and disabled when pTextBox is exited (this is working fine).

单击上下文菜单项时调用的代码为:

The code invoked when the context menu item is clicked is:

Public Function OnActionZoom() As Boolean

Dim ctl As Control

Set ctl = GetCurrentControl
'GetCurrentControl returns the current Control object on a form or subform and works fine

CallByName ctl.Parent, ctl.Name & "_DblClick", VbMethod

OnActionZoom = True

End Function

我在CallByName行上收到错误2465(找不到引用的字段").我假设这是因为DblClick代码在事件接收器中而不是在窗体中. ctl.parent和ctl.name设置正确.

I get an error 2465 ("can't find the field referred to") on the CallByName line. I'm assuming that this is because the DblClick code is in the event sink not the form. ctl.parent and ctl.name are set correctly.

我该如何编码以调用事件接收器代码?

How can I code this to invoke the event sink code?

更新:我尝试过在表单中​​创建一个空的(公共)Field_DblClick子目录;无济于事-这个空子程序会运行,但不会触发类模块中的事件.也不将myTextBox_DblClick设置为公开"而不是私有".

Update: I've tried creating an empty (Public) Field_DblClick sub in the form; doesn't help - this empty sub runs but the event in the class module doesn't fire. Neither does making myTextBox_DblClick Public instead of Private.

在这种情况下,我可以直接调用OpenZoomForm,或者可以有一个appZoomText公共实例,该实例可以根据需要与不同的文本框关联(我没有尝试过).

In this instance I could just invoke OpenZoomForm directly, or maybe I could have a single public instance of appZoomText that gets associated with different textboxes as required (I haven't tried this).

但是,我需要使用类似的方法来创建一个菜单项,以在多个组合框和文本框中进行下钻-双击组合框/文本框可在牛中为该项目打开一个编辑表单-但是编辑形式并不总是相同,而且每个事件接收器都不能有一个公共实例.

However, I need to use a similar method to create a menu item to drill-down in a number of comboboxes and textboxes -- double-clicking in the combo-box/textbox opens an edit form for the item in the ox -- but the edit form isn't always the same, and I can't have a single public instance of each event sink.

类似的代码:

Combobox_Enter或TextBox_Enter:

Combobox_Enter or TextBox_Enter:

dim mclsClass as ClassX
set mclsClass as new ClassX
set mclsClass.ComboBox = ActiveControl 'Or set mclsClass.textbox = activecontrol

在ClassX中:

    Private Withevents myComboBox as ComboBox 
    Public Property Set ComboBox (pctlComboBox as ComboBox)
       set myComboBox = pctlComboBox
       myComboBox.OnDblClick = "[Event Procedure]"
    End Property

   Private WithEvents myTextBox as TextBox
    Public Property Set TextBox(pctltextBox as TextBox)
       set myTextBox= pctltextBox
       myTextBox.OnDblClick = "[Event Procedure]"
    End Property

Public Sub myComboBox_DblClick(intCancel As Integer)
   If Not IsNull(KeyID(myComboBox.Text)) Then 'Check that there is a record to edit
       EditFormX(myComboBox) 'EditFormX depends on the Class 
       'Some more code in here depending on the user's edit
       myComboBox.Requery
   End If
End Sub

Public Sub mytextBox_DblClick(intCancel As Integer)
   If Not IsNull(KeyID(myTextBox.Text)) Then 'Check that there is a record to edit
       EditFormX(myTextBox) 'EditFormX depends on the Class 
       'Some more code in here depending on the user's edit
       myTextBox.Requery
   End If
End Sub

推荐答案

要使CallByName工作,您需要确保以下各项:

For CallByName to work, you need to ensure the following:

1)被调用的方法是公共的而不是私有的.

1) The method being called is public not private.

2)传递了所有必需的参数.

2) All required parameters are passed.

这样,您需要将事件处理程序公开(如您现在所做的那样),并为DblClick处理程序的Cancel参数传递一个附加参数到CallByName.由于您在方法本身内部不对该参数做任何事情,因此仅传递0即可:

As such, you need to make the event handlers public (as you are now doing), and pass an additional argument to CallByName for the DblClick handers' Cancel parameter. Since you aren't doing anything with that parameter inside the methods themselves, passing just 0 will do:

CallByName Ctl.Parent, Ctl.Name + "_DblClick", 0

更新1-此工作的示例[请注意,在OP的情况下,这太简单了-请参阅下面的更新2]

a)创建一个新的Access项目.

a) Create a new Access project.

b)向项目中添加一个新的空白表单,并向该表单中添加一个文本框.

b) Add a new blank form to the project, and a TextBox to the form.

c)在属性"窗口中双击文本框的On DblClick事件,如果出现提示,则选择代码生成器"选项.

c) Double click the text box's On DblClick event in the Properties window, choosing the Code Builder option if prompted.

d)为处理程序添加以下代码:

d) Add the following code for the handler:

Private Sub Text1_DblClick(Cancel As Integer)
  MsgBox "Hello World!"
End Sub

e)修改方法的标题,以使其读取Public Sub而不是Private Sub

e) Amend the method's header so that it reads Public Sub not Private Sub

f)查看(打开)表单,然后在其中单击以突出显示文本框.

f) View (open) the form, and focus the text box by clicking inside it.

g)返回VBA编辑器,并添加一个新的标准模块.

g) Go back into the VBA editor, and add a new standard module.

h)将以下子例程添加到模块中:

h) Add the following sub-routine to the module:

Sub Test()
  Dim Ctl As Access.Control
  Set Ctl = Screen.ActiveControl
  CallByName Ctl.Parent, Ctl.Name + "_DblClick", VbMethod, 0
End Sub

i)将插入号插入测试"例程中,按F5或单击运行"按钮

i) With the caret inside the Test routine, press F5 or click the Run button

关于此,"Hello World"消息会为我显示.

On this, the 'Hello World' message appears for me.

更新2

现在显式使用WithEvents,可以演示在您遇到的情况下可能起作用的示例:

With the use of WithEvents now explicit, a demo of something that may work in your situation:

1)在Access中,创建一个新数据库并向其中添加一个空白表格.

1) In Access, create a new database and add a blank form to it.

2)在表单中添加一个文本框和一个组合框,然后调用txtTestcboTest;接下来,添加三个命令按钮,分别将其命名为cmdCreateControllerscmdDestroyControllerscmdExecuteController,并将其标题设置为创建控制器",销毁控制器"和执行控制器".还将cmdDestroyControllerscmdExecuteControllerEnabled属性设置为False.

2) Add a text box and a combo box to the form, and call then txtTest and cboTest; next, add three command buttons, calling them cmdCreateControllers, cmdDestroyControllers and cmdExecuteController respectively, and setting their captions to 'Create controllers', 'Destroy controllers' and 'Execute controller'. Also set cmdDestroyControllers and cmdExecuteController's Enabled properties to False.

3)在VBA编辑器中,添加一个类模块,将其重命名为IController,然后添加以下代码:

3) In the VBA editor, add a class module, rename it IController, and add the following code:

Option Explicit

Sub Execute()
End Sub

这是我们的接口类型(即抽象类定义).

This is our interface type (i.e., abstract class definition).

4)通过工具|参考...",添加对"Microsoft Scripting Runtime"的引用,我们不久将使用它的Dictionary类.

4) Via Tools|References..., add a reference to 'Microsoft Scripting Runtime', of whose Dictionary class we will shortly be using.

5)向其中添加一个标准模块,并添加以下代码:

5) Add a standard module, and the following code to it:

Option Explicit

Private mControllers As New Scripting.Dictionary

Sub RegisterController(Obj As Object, Controller As IController)
  mControllers.Add Obj, Controller
End Sub

Sub UnregisterController(Obj As Object)
  mControllers.Remove Obj
End Sub

Function GetController(Obj As Object) As IController
  Set GetController = mControllers(Obj)
End Function

Function IController_Initialize(Controller As IController, _
  OldObj As Object, NewObj As Object) As Object
  If Not (NewObj Is OldObj) Then
    If Not (OldObj Is Nothing) Then UnregisterController OldObj
    If Not (NewObj Is Nothing) Then RegisterController NewObj, Controller
  End If
  Set IController_Initialize = NewObj
End Function

这里的最后一个功能是IController实现的助手.现在让我们创建一对-

The last function here is a helper one for IController implementations. Let's now create a couple -

6)添加另一个类模块,将其重命名为MyTextBoxController,并添加以下代码:

6) Add another class module, rename it MyTextBoxController, and add the following code:

Option Explicit

Implements IController

Private WithEvents mTextBox As Access.TextBox

Property Set TextBox(NewValue As Access.TextBox)
  Set mTextBox = IController_Initialize(Me, mTextBox, NewValue)
  If Not (mTextBox Is Nothing) Then mTextBox.OnDblClick = "[Event Procedure]"
End Property

Private Sub mTextBox_DblClick(Cancel As Integer)
  IController_Execute
End Sub

Private Sub IController_Execute()
  MsgBox "Hello from the example text box controller!"
End Sub

7)添加另一个类模块,将其重命名为MyComboBoxController,并添加以下代码:

7) Add another class module, rename it MyComboBoxController, and add the following code:

Option Explicit

Implements IController

Private WithEvents mComboBox As Access.ComboBox

Property Set ComboBox(NewValue As Access.ComboBox)
  Set mComboBox = IController_Initialize(Me, mComboBox, NewValue)
  If Not (mComboBox Is Nothing) Then mComboBox.OnDblClick = "[Event Procedure]"
End Property

Private Sub mComboBox_DblClick(Cancel As Integer)
  IController_Execute
End Sub

Private Sub IController_Execute()
  MsgBox "Hello from the example combo box controller!"
End Sub

8)返回表单并按如下方式处理cmdCreateControllers'Click事件:

8) Go back the form and handle cmdCreateControllers' Click event as thus:

Option Explicit

Private mTextBoxController As MyTextBoxController, mComboBoxController As MyComboBoxController

Private Sub cmdCreateControllers_Click()
  If mTextBoxController Is Nothing Then Set mTextBoxController = New MyTextBoxController
  Set mTextBoxController.TextBox = txtTest
  If mComboBoxController Is Nothing Then Set mComboBoxController = New MyComboBoxController
  Set mComboBoxController.ComboBox = cboTest
  cmdDestroyControllers.Enabled = True
  cmdExecuteController.Enabled = True
End Sub

9)处理其他两个按钮的单击事件,如下所示:

9) Handle the other two buttons' Click events like this:

Private Sub cmdDestroyControllers_Click()
  cmdCreateControllers.SetFocus
  cmdDestroyControllers.Enabled = False
  cmdExecuteController.Enabled = False
  Set mTextBoxController.TextBox = Nothing
  Set mComboBoxController.ComboBox = Nothing
End Sub

Private Sub cmdExecuteController_Click()
  Dim Name As String
  Name = InputBox("Enter the name of the control whose controller you want to execute:")
  If Name = "" Then Exit Sub
  GetController(Me.Controls(Name)).Execute ' add error handling as desired!
End Sub

10)打开表单,然后双击文本框或组合框-什么也不会发生.

10) Open the form, and double click either the text box or the combo box - nothing should happen.

11)单击创建控制器",然后再次双击:应显示一个消息框.

11) Click Create Controllers, and double click again: a message box should show.

12)单击执行控制器",然后输入txtTest:将会再次显示一个消息框.

12) Click Execute Controller, and enter txtTest: a message box should again show.

13)取消挂钩自定义事件接收器,并通过单击销毁控制器将其注销为对象控制器;完成此操作后,双击任何一个主题控件都应该再次不执行任何操作.

13) Unhook the custom event sinks and unregister them as object controllers by clicking Destroy Controller; having done that, double clicking either of the subject controls should once more do nothing.

这篇关于将CallByName与“事件接收器"一起用于表单上的字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆