此处的内容可能适用于 Northwind 2.0 Developer Edition 和 Starter Edition。
VBA (Visual Basic for Applications) 是所有 Office 产品中使用的编程语言。 学习 VBA 使你能够使用所有 Office 产品 (而不仅仅是 Access) 。搜索“作方法”时,请务必查找 Access 特定示例,并在搜索中包含 Microsoft Access。 通常,其他 Office 产品的解决方案会奏效,但无法保证。 Microsoft Access 是一种成熟的产品;这意味着有很多示例:这很适合你!
这也意味着有关 Access 编程的旧书籍仍然可供你查看。 许多较旧的书籍仍然以原始成本的一小部分在二手书网站上提供。 查看Microsoft网站,确定哪些版本的 Access 仍受支持,并使用这些版本。
终止 Office 支持资源 - 部署 Office |Microsoft Learn
下面是 Microsoft 上的 Access 文档的一些链接。
Microsoft Access 文件是 Office 文件。 Office 文件必须位于“受信任位置”或“已启用其内容”。 这些项目被视为“安全”,因为你创建了它们,或者它们来自可信的来源。 每次打开任何 Office 文件时,都会检查受信任位置。 我们将从此处将其称为“受信任/已启用”。 注意:如果从不受信任的位置发布并打开应用程序的新版本,则启用内容的过程将重复。
详细了解受信任位置。:
宏、函数和子项是将业务逻辑实现到 Access 数据库的方式。 在开始之前了解 范围和可见性 非常重要。
事件 ((如单击窗体上的控件) 控件 (例如按钮、文本框、标签等)) 触发其他过程,例如添加、删除记录或打开窗体。 可以使用宏或 VBA 实现这些过程。 Northwind Starter Edition 主要使用宏,而某些 VBA 则宏无法执行所需的功能。 Northwind Developer Edition 主要使用 VBA。
某些控件类型具有用于自动创建宏的内置向导。 例如,向窗体添加命令按钮会打开一个向导,该向导为按钮提供多个功能选择。 添加组合框将打开一个向导,该向导可以配置为在窗体上查找特定记录。
导航窗格是查看和访问所有数据库对象的main方式,默认情况下,它显示在 Access 窗口的左侧。 已自定义 Northwind 导航窗格。 我们创建了一个名为 Northwind Starter 2.0 的自定义类别。 这使我们能够按功能区域组织对象。
了解 Access/Office 中的 范围和可见性 非常重要。 可以从此处开始:
有时,在创建变量的对象超出范围后,需要存在变量。 请参阅上面的 范围和可见性 。 有三种主要方法可以执行此作:公共变量、TempVar 和将值存储在本地表中。 许多开发人员混合使用这些组合。 每个都有其优缺点。 有关每个内容的详细信息,请参阅此处:
VBA 模块公共变量:
TempVars:
将值存储在本地表中
-
当前会话存在公共变量和 TempVar,在应用程序关闭时超出范围。 但是,如果要跨会话保留特定于用户的变量,该怎么办? 可以将这些类型的值存储在本地表中。 在 Northwind 2.0 中,一个此类变量保存在名为 SystemSettings 的表中。 表中的值为 ShowWelcome。 此值指示 Access 是否要在每次登录时看到欢迎屏幕。
开发人员通常需要将参数从一个窗体传递到另一个窗体,或者从窗体传递到报表。 这些参数传达重要信息,然后被调用的函数将使用这些信息来配置自身。 第二个窗体或报表可通过多种方式从第一个窗体获取信息。 下面是以下几种方法:
-
第二个窗体可以“回头看”到第一个窗体,以选取一些值,这些值可能位于可见控件或不可见控件中。 例如: lngCustomerID = Forms!FirstForm!cboCustomerID
-
第一个窗体可以将值保存到全局变量或 TempVars。 例如: g_lngUserID = Me.cboUserID TempVars.Add “UserID”、Me.cboUserID
在 Northwind Developer Edition 以及我们的职业生活中经常使用的方法是使用 DoCmd.OpenForm 或 OpenReport 的 OpenArgs 参数。 例如: DoCmd.OpenForm "frmCompanyDetail", OpenArgs:=StringFormat("CompanyID={0} &CompanyTypeID={1}", Me.VendorID, ctVendor)
我们在这里组合了两种技术: (1) 使用 OpenArgs 传入 VendorID 和 VendorType, (2) 使用 StringFormat () 函数创建,例如,此字符串:
CompanyID=5&CompanyTypeID=2
此字符串与浏览器中使用的查询字符串非常相似。 它包含一个或多个用和号字符分隔的“名称/值对”:
name1=value1&name2=value2
此类字符串的优点是每个值都有一个名称。 将此与将 OpenArgs 仅设置为“5,2”的更简单方法进行比较。 在这种情况下,需要努力找出每个值所表示的内容。 命名每个值会使查询字符串“自我描述”,这是一个很好的编程做法。
在 DoCmd.OpenForm 的接收端,我们通常位于 Form_Open 或 Form_Load 事件中,并希望将 OpenArgs 字符串分析为其组件。
在 Northwind 中,可以使用 StringToDictionary 函数执行此作。 它采用类似于查询字符串的函数,并将其分析为其组件。 然后,这些组件存储在 Scripting.Dictionary 对象中。 请注意,执行此作需要使用 工具 > 引用 ,并将引用设置为 Microsoft脚本运行时 (scrrun.dll) 。
Dictionary 对象的功能和优点包括:
-
元素的顺序并不重要
-
用于添加和删除集合元素的简单函数
-
要循环访问集合的函数,以便可以知道其中的内容
-
Exists 函数,以便测试某个元素是否可用
字典对象的使用将出现在整个 Northwind 中。 例如,frmGenericDialog 中的 Form_Load 事件。
使用 Access 中的控制向导创建的宏很少包括错误处理;使用控件向导创建的 VBA 可能仅限于泛型 MsgBox Err.Description。
在 Northwind 2.0 中,我们向你介绍如何在使用 VBA 代码时做得更好。 我们实现了所谓的 全局错误处理程序。 任何过程中发生的错误都会调用全局级别的函数来显示错误。 此处的最大优势是错误处理是一致的。 如果消息需要更改 (例如,为了额外显示错误编号或将错误记录到) 文件,则只需在一个位置完成。
clsErrorHandler 是实现错误处理代码的类模块。 类模块将其所有main和帮助程序函数保存在一个单元中,从而封装代码。
AutoExec 宏调用 modStartup 中的 Startup 函数。 在 Starter Edition 中,函数创建 clsErrorHandler 的实例,并将其保存为全局变量,可供整个应用程序使用。 在开发版本中,使用静态类 - 请参阅类模块顶部的注释。
事实上,过程中的错误处理代码非常一致,以至于我们能够在不到五分钟内使用特定的 VBA 代码创建所有代码,这些代码为每个过程配置了正确的错误处理程序。 (代码未包含在模板) 中。 Northwind 2.0 初学者版和开发人员模板版本最初都配备了这种错误处理方法。 '
改进了错误处理
从 Northwind Developer Edition 版本 2.2 开始,由于 Access 社区的反馈,错误处理程序得到了改进。 初学者版本保持不变。
实质上,2023 年 4 月发布的早期版本 (2.0 中的错误处理程序) 为:
Public Sub HandleError(…) MsgBox Err.DescriptionEnd Sub
在版本 2.2 中,它已升级到:
Public Sub HandleError (…, Optional ByVal IsEventProcedure As Boolean = False) If Not IsEventProcedure Then Err.Raise lngError, strErrSource End If MsgBox Err.DescriptionEnd Sub
为了了解此更改的原因,我们首先了解代码运行的原因:
-
AutoExec 宏调用 Startup 过程,该过程在打开第一个窗体之前执行一些初始化。
-
用户与应用程序交互,例如打开窗体或单击按钮,导致事件过程触发,例如 Form_Load 和 cmdPrintInvoice_Click。 '
除了事件过程,应用程序还具有子例程和函数(主要是在模块中),并且该代码是从事件过程调用的。 这些过程称为“标准”过程。
在 Northwind 2.0 版中,标准过程会处理自己的消息错误,但不会以某种方式通知调用事件过程发生了错误。 如果事件过程具有应运行的后续代码,而不考虑被调用过程处理过以前的错误,则这种情况可能会很糟糕。 当然,我们可以将子例程替换为返回成功或失败的函数,并相应地编码事件过程,但这并不总是一个选项。
在 Northwind 版本 2.2 中,标准过程不处理错误消息,而是使用 Err.Raise 将它们报告回调用事件过程。 然后,调用事件过程会显示引发的错误,并在 Exit_Handler恢复。 这更好,因为它允许调用过程正常结束。
若要使用 Northwind 版本 2.2 代码,事件过程必须向 HandleError 传递第三个参数,以指示调用方是事件过程。 Northwind Dev Edition 已更新为执行此作。
更强大的错误处理程序模块将支持“堆栈” (数组) 上的“推送和弹出”过程。 第一个元素始终是事件过程,因此不需要额外的参数。 此实现超出了 Northwind Dev Edition 的目标。
MRU 或 最近使用的 订单是最近使用的订单和采购订单的列表。 你可能想要经常返回到这些内容,以将它们置于下一个状态中。 MRU 列表在 Office 产品中通常显示为最近使用的文件列表,你可能希望再次重新打开。
在 Northwind Dev Edition 中,若要实现在 Starter edition) 中不存在的 MRU 功能 (必须先建立以下项:
-
用于存储 MRU 信息的表。
-
打开订单或采购订单 (PO) 时更新表的代码。
-
用于更新功能区中的 MRU 下拉列表的代码。
-
从功能区中选择 MRU 项时用于加载项的代码。
让我们更详细地了解其中的每一个。
1. 用于存储 MRU 信息的表。
表 MRU 的设计值得回顾,尤其是其索引。 请注意,有一个重复的索引 SortIdx 来帮助快速排序功能区下拉列表中的 MRU 项目,以及一个唯一的索引来强制实施业务规则,即每个用户的项只能发生一次。 例如,打开同一顺序两次不会在 MRU 表中创建两条记录。
该表利用了数据库中所有与 MRU 相关的 PK (主键) 字段都是自动编号这一事实,因此长整数数据类型可用于 PKValue。
2. 在打开订单或 P.O. 时更新表的代码。
在 NW2 中,我们选择仅在创建新记录时(而不是再次更新现有记录时)添加到 MRU 列表。 我们当然可以将 AddToMRU 调用从 Form_AfterInsert 转移到 Form_AfterUpdate 以支持这一点。
AddToMRU 和 DeleteFromMRU 过程在 modGlobal 中实现,这是一个Standard模块,其公共过程可从任何形式可见。
AddToMRU (顾名思义,) 将新项添加到 MRU 表,然后选择性地剪裁它,如果其增长超过最大大小 (MAX_MRU_COUNT) ,则删除最早的记录。 最后一步可能是 Access 开发人员最不为人知的步骤:必须刷新功能区下拉列表,并通过调用 InvalidateControl 来完成。 这是向功能区发出重新运行其初始化过程的信号。
3. 用于更新功能区中的 MRU 下拉列表的代码。
在启动时,在调用 InvalidateControl 后,将执行一组复杂的函数来填充功能区。 这些过程由表 uSysRibbons 中的功能区 XML 调用,其中部分显示:
<group id="gCurrentStatus" label="MRU">
<box id="bxMRU" boxStyle="vertical">
<dropDown id="ddMRU"
getItemCount="ddMRU_GetItemCount"
getItemLabel="ddMRU_GetItemLabel"
getSelectedItemIndex="ddMRU_GetSelectedItemIndex"
getItemID="ddMRU_GetItemID"
onAction="ddMRU_OnAction"
screentip="Most Recently Used Objects">
</dropDown>
</box>
</group>
这四个回调函数将填充下拉列表。 请注意,这与 此处所述的标准组合框的概念非常相似。
如果在 modRibbonCallback 中取消注释 Debug.Print 行并重启应用程序,则即时窗口将显示如下所示的序列:
ddMRU_GetItemCount ddMRU 6
ddMRU_GetItemLabel ddMRU 0 Order 60, Proseware, Inc.
ddMRU_GetItemID ddMRU 0 2
ddMRU_GetItemLabel ddMRU 1 Order 62, Best For You Organics Company
ddMRU_GetItemID ddMRU 1 4
ddMRU_GetItemLabel ddMRU 2 Order 63, Wide World Importers
ddMRU_GetItemID ddMRU 2 5
ddMRU_GetItemLabel ddMRU 3 Order 66, Proseware, Inc.
ddMRU_GetItemID ddMRU 3 8
ddMRU_GetItemLabel ddMRU 4 Order 67, Best For You Organics Company
ddMRU_GetItemID ddMRU 4 9
ddMRU_GetItemLabel ddMRU 5 Order 68, Adatum Corporation
ddMRU_GetItemID ddMRU 5 10
ddMRU_GetSelectedItemIndex ddMRU 0
在这里可以看到,Access 首先调用一个过程,该过程返回 ddMRU_GetItemCount的 ByRef 参数中要加载的项数。 这也是我们对 MRU 表打开查询并缓存它的时间,因为它即将使用多次。
然后,功能区会重复调用两个过程来获取两列下拉列表的 ID 和 Label 值。
最后,它调用一个过程来取消应选择的项。 (在本例中,它是第一个.)
4. 从功能区选择 MRU 项时用于加载项的代码。
与任何其他功能区项一样,功能区 XML 中的 OnAction 属性指定用于执行作的回调函数:
onAction="ddMRU_OnAction"
此过程在 modRibbonCallback 中实现。 它重新使用已打开的记录集来查找包含所选项目的记录,然后,根据所需的 TableName 打开相应的窗体,并传入要加载的 PK 值。
-
Northwind 2.0 Developer Edition: Template-Tutorial
-
Northwind 2.0 Developer Edition:所有主题