表设计
Access数据表能做什么
2017-02-20 14:55:41

你可以做到的数据表?

Office 2003

你可以做到的数据表?

迈克尔·卡普兰

每个使用数据表的人都知道他们是强大的,但很少有人知道你能用他们做的所有事情。迈克尔·卡普兰从解锁的Access 97向导中掏出一些技巧,可以帮助你真正得到这些有用的项目最好的。

Visual Basic开发人员承认,即使最残酷的事情之一是他们希望Visual Basic有一个像Access的数据表一样强大的网格。有了所有的力量,还有很多事情,没有人知道如何与他们。开发人员常常忽略数据表,他们似乎喜欢连续表单。

然而,数据表提供了一种简单而强大的方式来向用户显示数据。数据表还允许您提供用户界面(UI),您的用户可以配置以满足他们的需要。大多数开发人员认为数据表给予用户太多的控制。但是,通过控制您的数据表,您可以将它们合并到您的应用程序中。在本文中,我将展示这些强大的UI对象的一些功能,大多数开发人员不理解。

使用“sorta隐藏”属性

数据表有很多属性,仅适用于它们,如表1所列。

表1. Access中与数据表相关的属性。

属性含义和用法
ColumnHidden存在于数据表中的列上,控制列是否可见。
ColumnOrder存在于数据表中的列上,控制显示列的顺序。
列宽存在于数据表中的列上,控制列的宽度。
数据表颜色存在于数据表本身,指定整个数据表的背景颜色。
DatasheetCellsEffect存在于数据表本身,处理是否为单元格使用特殊效果(平面,凸起或凹陷是唯一支持的效果)。
数据表FontHeight存在于数据表本身,这不幸的命名属性指定字体大小。
数据表存在于数据表本身上,控制是否所有文本都是斜体。
数据表存在于数据表本身,控制字体的名称。
数据表FontUnderline存在于数据表本身上,控制是否所有文本都加下划线。
数据表存在于数据表本身,控制文本是否加粗。
DatasheetForeColor存在于数据表本身,指定整个数据表的前景色。
数据表存在于数据表本身,控制将显示哪些网格线(如果有)。
数据表存在于数据表本身,指定网格线的颜色。
FrozenColumns存在于数据表本身,指定用户冻结了多少列(本文后面讨论)。
ShowGrid存在于数据表本身,但已被DatasGridlinesBehavior属性取代。
SubdatasheetExpanded存在于数据表本身上,指定是否应扩展所有子数据表。(仅限访问2000)
SubdatasheetHeight存在于数据表本身上,指定为子数据表显示的记录数(如果该属性允许的记录数更多,则显示滚动条)。(仅限访问2000)
SubdatasheetName存在于数据表本身上,指定表的子数据表的名称。(仅限访问2000)
TabularCharSet存在于数据表本身,并被隐藏。它指定字体字符集,如果设置为不正确的值,通常可能会导致不良后果。最好不要设置它,或将其设置为1(使用机器的DEFAULT_CHARSET)。

除了Subdatasheet属性之外,您没有对这些属性的直接设计时访问权限:这些属性都不显示在数据表的属性表中。因此,它们只能在运行时从VBA代码设置为了进行更改。有趣的是,没有一个属性是暴露的ADO或ADOX,所以如果你想改变它们,你必须使用DAO。

虽然无法通过属性表访问这些属性,但可以在用户界面中设置其中的许多属性。例如,当您从“格式”菜单中设置数据表的字体时,会发生什么变化。然而,为了完全控制数据表,您需要在代码中显式设置属性,并在完成后保存对象。

值得注意的是,数据表是一种形式 - 它在对象浏览器中如此正确。对象浏览器将数据表的列视为表单上的控件。因此,数据表可以包含可以显示的任何控件,这意味着所有TextBox,ComboBox和CheckBox控件。

好的,足够的介绍; 我想向你展示一些你可以做的数据表。显然,许多数据表属性不需要解释:任何人都可以知道字体或网格属性。相反,我会移动到不太明显的兴趣项目...

在运行时隐藏列

有时,您想要隐藏数据表中的特定列。例如,Access ListBox / ComboBox向导执行此操作。该向导使用通用的20列数据表作为其用户界面的一部分。向导隐藏特定列以将其显示限制为适合示例数据的列数。即使你的需求不是那么壮观,你可能想在每个显示器上隐藏所有相关的列。您甚至可能想在数据表的顶部提供一堆复选框,以允许用户隐藏和显示列。我个人发现这种用户可配置的UI真的很有趣。

要在操作中看到这一点,可以在随附的下载文件中的示例数据库中查看frmHideShowColumns和sfrmHideShowColumns。子表单只是一个基于Northwind的Products表的简单数据表,而窗体未绑定,并包含复选框以显示和隐藏子表单上的各个列。frmHideShowColumns表单看起来像图1

事实上,这种形式的大部分工作只是在命名所有的控件(我使用“ck”作为前缀的每个复选框在主窗体上,“tb”作为每个文本框的子窗体的前缀,以及窗体和子窗体上的其余绑定控件的实际字段名称)。一旦适当的名称到位,只剩下两个步骤:

  1. 选择所有的复选框,然后添加一个调用我写的程序ShowHideColumns( 见图2)。

  2. 在表单后面添加代码,以确保在加载表单时检查正确的复选框,并且每当CheckBox值更改时更新表单。检查复选框的代码是在Form_Load事件中:

Private Sub Form_Load() Dim ctl As Control Dim stCtl As String Set sfrm = Me.sfrmHideShowColumns For Each ctl In Me.Controls If TypeOf ctl Is Access.CheckBox Then stCtl = "tb" & Mid$(ctl.Name, 3) ctl.Value = Not sfrm.Form(stCtl).ColumnHidden End If Next ctl End Sub

显示和隐藏列的代码在一个名为ShowHideColumn的例程中。你会注意到它看起来很像Form_Load事件中的代码:

Private Function ShowHideColumn() Dim sfrm As SubForm Dim ctl As Control Dim stCtl As String Set sfrm = Me.sfrmHideShowColumns For Each ctl In Me.Controls If TypeOf ctl Is Access.CheckBox Then stCtl = "tb" & Mid$(ctl.Name, 3) sfrm.Form(stCtl).ColumnHidden = _  Not ctl.Value End If Next ctl End Function

Voilà!您现在可以按需显示和隐藏列!

你当然可以扩展这种技术。这里有一些建议的方法来增强功能:

  • 而不是在更改一个列时触摸每个列,您可以在ShowHideColumns函数中使用一个包含控件名称的参数。

  • 您可能希望永远显示某些列。

  • 某些列可能始终需要保持可见。

重新定位列 - 不!

相信或不,一旦用户开始意识到他们可以重新配置他们的UI,他们不能得到足够的。许多用户知道,他们可以只是将鼠标粘在列的标题,单击以选择,并拖动列周围。简单!但是,如果结果不适合应用程序,这可能是非常恼人的 - 尤其是如果他们保存这些更改!

问题是,有时候你想确保你的用户不能对你的数据表的布局做出戏剧性的改变。例如,您可能需要确保某些数据始终可见。不幸的是,没有固定位置的列的属性。但是,您可以使用与控件相关联的事件获得相同的效果。

要控制重新定位,您需要在数据表中使用控件的MouseUp事件。按照我在上一节中描述的方式( 如图2所示),将所有列的属性设置为单个过程,然后使用以下过程防止列漫游:

Private Function DontMuckWithSize() Dim ctl As Control Dim ictl As Integer For ictl = 0 To Me.Controls.Count - 1 Set ctl = Me.Controls(ictl) If TypeOf ctl Is Access.TextBox Then ctl.ColumnOrder = ictl + 1 End If Next ictl End Function

此代码利用数据表的Controls集合。当用户可以在屏幕上重新定位列时,控件集合中的列的位置与最初显示表单时的位置不会发生变化。代码只循环遍历集合,将每个列的ColumnOrder设置回控制集合中的位置。被添加到ictl变量的1正是在那里处理控件集合中的位置(基于0)和ColumnOrder数(它是1基于)的差异。您可以在示例数据库中的frmNoReposition表单中查看此操作。

你显然可以使用ColumnOrder属性更多。此示例总是将它们重新排序为原始顺序,而您实际上可能希望将列移动到新位置。实际上,您可以组合ColumnOrder和ColumnHidden来生成各种复杂的方案,允许您跨多种形式重用相同的子表单。您所要做的就是使用这些属性来改变数据表中特定字段的强调。我的一个建议是确保您的更改是直观的。它可以非常令人不安的用户让事情移动的飞行。你通常应该限制这些技术在表单加载时改变布局,然后单独留下UI。

现在,高级开发人员不得不处理这个问题,知道有一种情况不是由这种代码处理。如果用户从“格式”菜单中选择“冻结列”,则所选列将一直移动到屏幕的左侧,并固定在那里,无论您如何在数据表中移动(类似于Excel的列冻结功能) 。您可以通过查看FrozenColumns属性来检测这种情况,该属性指示冻结了多少列(它将始终以1开头,因为Access将记录选择器计为一个始终冻结的列)。如果要冻结或取消冻结代码中的列,可以使用DoCmd.RunCommand,传递acCmdFreezeColumn和acCmdUnfreezeAllColumns作为参数。

此功能缺少的是一个事件,通知您用户已冻结了某些列,并且每个列上还有一个属性,告诉您哪些列已冻结。如果要控制哪些列被冻结,您必须检查FrozenColumns属性以查看该数字是否错误,解冻所有列,然后冻结所需的列。

调整列大小

以编程方式调整列以显示列中当前数据的能力是我想写这篇文章的原始原因:这只是一个了不起的功能。我看到的第一个地方是Access的规范化,更好地称为访问表分析器(所有的向导的对象的名称仍然以“NORM_”为前缀,因为市场对“表分析器”的更改没有强制任何代码变化!)。规范器使用DAO创建查询,然后将结果数据表的列设置为适当的宽度,以在列中显示数据。并且请记住,Access中的表和查询使用数据表(至少在浏览视图中有这些表时)显示,这是表单。

将列自动调整为当前数据大小的技巧需要两个步骤:

  1. 您必须将数据表的ColumnWidth属性设置为-2,这在内部是一个似乎意味着“最适合”Access的数字。然后,Access将会将ColumnWidth属性值更改为适当的数字(以缇为单位)。

  2. 要使更改永久,您必须向DAO的Property集合(不包含所有查询的默认属性)中添加一个名为ColumnWidth的属性,并将该属性的值设置为与步骤1中控件的ColumnWidth属性相同的值。

要做到这一点,你可以使用我的程序FixColumnWidthsOfQuery或FixColumnWidthsOfTable和他们有帮助的子程序SetDAOFieldProperty:

Public Function FixColumnWidthsOfQuery _  (stName As String) Dim db As Database Dim qdf As QueryDef Dim fld As DAO.Field Dim frm As Form Dim ictl As Integer Dim ctl As Control Set db = CurrentDb Set qdf = db.QueryDefs(stName) DoCmd.OpenQuery stName, acViewNormal Set frm = Screen.ActiveDatasheet For ictl = 0 To frm.Controls.Count - 1  Set ctl = frm.Controls(ictl)  ctl.ColumnWidth = -2  Call SetDAOFieldProperty(qdf.Fields(ictl), _ "ColumnWidth", ctl.ColumnWidth, dbInteger) Next ictl DoCmd.Save acQuery, stName End Function Public Function FixColumnWidthsOfTable _ (stName As String) Dim db As Database Dim tdf As TableDef Dim fld As DAO.Field Dim frm As Form Dim ictl As Integer Dim ctl As Control Set db = CurrentDb Set tdf = db.TableDefs(stName) DoCmd.OpenTable stName, acViewNormal Set frm = Screen.ActiveDatasheet For ictl = 0 To frm.Controls.Count - 1  Set ctl = frm.Controls(ictl)  ctl.ColumnWidth = -2  Call SetDAOFieldProperty(tdf.Fields(ictl), _ "ColumnWidth", ctl.ColumnWidth, dbInteger) Next ictl DoCmd.Save acTable, stName End Function Private Sub SetDAOFieldProperty _  (fld As DAO.Field, _  stName As String, vValue As Variant, _  lType As Long) Dim prp As DAO.Property For Each prp In fld.Properties If StrComp(prp.Name, stName, _  vbBinaryCompare) = 0 Then prp.Value = vValue Exit For End If Set prp = Nothing Next prp If prp Is Nothing Then Set prp = fld.CreateProperty(stName, _  lType, vValue) fld.Properties.Append prp End If End Sub

您可以简单地将任何表或查询的名称传递给这些例程,并让他们完成其余操作!

如果你需要使用Form来完成同样的任务,那就更容易:只需将所有ColumnWidth属性设置为-2即可。不需要额外的步骤。

结论

真的,本文只涉及数据表的表面。展望Access 2000,有一些新的功能可用于数据表:

  • 条件格式允许您更改单个单元格基于其值(长期请求的功能)的格式化方式。鉴于有多少人仍在使用Access 97,我通常建议人们使用斯蒂芬·黎巴嫩的解决方案这个问题,因为他的意志将工作在Access 95,97和2000。

  • 子数据表是一种强大的功能,可以用来非常有效地显示层次数据。像我讨论的其他功能,他们依赖于Jet属性,只能通过DAO创建/修改。不幸的是,如果您需要此功能,您必须升级到Access 2000。

  • 对于Access 2000,Access团队的开发人员注意到数据表在许多意义上是“表单”(使用ActiveDatasheet属性将表和查询视为表单的主要原因)。Access 2000更进一步地支持在Subform控件中将表和查询直接用作SourceObject。您可以利用此更改来减少项目中所需的表单数量,直接将表和查询直接分配给子表单(修改属性,如运行时的ColumnWidth和ColumnHidden以更改其外观和感觉)。

很明显,数据表在他们背后有一些真正的力量,在客户如何使用它们以及他们如何操纵你。您可能会发现一个或多个这些提示有用,甚至被启发从Access中的数据表找到其他有用的功能!

本文摘自2001年2月发行的Smart Access。版权2001,由Pinnacle Publishing,Inc.,除非另有说明。保留所有权利。