摘 要:全面诠释Delphi中各种查询输入方法中的疑点。
“查询输入”,是指数据表中某字段的值来源于另一张表,编程时将“查询数据”源表与某个列表框捆绑起来,用户操作时中“查询”该列表框来实现输入,这是数据库编程中常用的技术,但一般资料上,没有详细介绍以上各种方法的使用细节,相反,有些资料上误导读者,尤其是在对DbGrid控件的处理上更是错误百出,疑点较多,使我们在编程中经常性遇到麻烦,笔者经过尝试,将以上方法一一摸透,关键地方一一点破,疑点难点予以破解。“查询输入”在Delphi 中实现方式有:
l 在建立表结构时从Table Properties中选Table LookUp可实现该功能;
l 通过Master(主要)/Detail(明细)窗体,以“多对一”关联操作来实现此功能
l 在表的Field Editor.(字段编辑器)中新建一个LookUp字段,用DbGrid(网格控件)或单个DbEdit控件来实现此功能。
l DataControls选项卡选择DbLookupCombobox来实现此项功能,该方法只能用在DbEdit控件上。
l 如果Lookup字段的取值不多,或者在程序运行中是固定不变的,则一个Dbgrid控件的列对象上捆绑一个下拉列表框,在其PickList属性中添入该Lookup字段的不同取值及DbListBox与DbCombobox。
一、利用表结构窗体中Table Lookup实现“查询输入”
如果你的数据量不大,又不想编程序,则可此方法直接在数据库桌面(DataBase DeskTop)中实现“查询输入”,
实例:课程表Class.db中的TNO字段的值,是教师表Teacher.db中TNO字段的值,现在建立为Class.db的TNO字段建立其“查询输入”方式。操作步骤如下:
在数据库桌面(DataBase Desktop)中打课程表,如D:\989101\CTC\DB\CLASS.DB,进入结构修改窗口à从Table Properties中选Table Lookupà单击“Define”按钮,进入如图“Table LookUP”所示的设置窗体,按如图所示方式设置好,存盘结束结构重构窗体,à进入Class表的“编辑”状态,在其TNO字段上,按Ctrl+Space键可弹出Teacher.db供你选择à有一点要请注意,在Windows中Ctrl+Space是中英文切换键,所以要在Windows的控制面板选“输入法”,将其“关闭/打开输入法”的热键从Ctrl+Space换成其它形式,如Alt+Space,这样不会与Delphi 发生冲突了。
该方法一般用于临时输入少量数据,如果想删除该功能,可进入“表结构重构”窗体中,选中TNO字段à选Table PropertiesàTable Lookupà这时TNO的查找表Teacher.db会显示出来à单击Erase按钮。
可为一张表的多个字段建立查找表。
二、Master(主要)/Detail(明细)窗体实现“查询输入”
Master/Detail主要用于像发票、财务凭证、入库单等数据的处理过程中,一张发票上日期、发票号、收款人等Master(主要)信息在一张发票中仅出现一次,但所购物品的名称、单价、规格Detail(明细)信息会出现多次,这种“主要/明细”操作,从数据库角度来看,它属于“一对多”关联操作。
我们“逆用“该技术,即变成“多对一”,利用“多对一”关联操作,也可以实现“查询输入”。其操作界面如下图所示,你输入一个TNO字段的值,在其下方显示其相关的数据,帮助你做出正确判断,这种方式在财务类软件较活用。
本例中涉及到两张表是:Class.db的结构是CNo S、Cname A(20)、Cdate De、CHour S、Cfeeph N、CcostPh N、Tno S,主键是Cno;Teacher.db的结构是 Tno S、Tname A(8)、Tadd A(20)、Tzip I、Ttel A(20),主键是Tno。均保存在C:\db目录中。
实例:要求Class.db表中的Tno字段用“查询输入”方式输入,下面操作步骤如下:
1、新建一个项目文件àFileàNewàData Moduleà建立一个数据模块à添加如下表所示的对象à根据下表设置各对象的属性à以Dmod1.Pas存盘。
对象名 |
属性值 |
Table1 |
DataBaseName=C:\db TableName=Class.db Active=True |
DataSource1 |
DataSet=Table1 |
Table2 |
DataBaseName=C:\db TableName=Teacher.db MasterSource=DataSource1
MasterField=Tno Active=True |
DataSource22 |
DataSet=Table2 |
在设置Table2的MasterFields会弹出“Field Link Designer”对话框,你必须先在“Detail Fields”的下方选中TNO字段,然后在Master Fields的下方选中Tno,再单击Add按钮,最后OK按钮。
2、在Form1中添加2个网格对象à并按F12切换到其代码窗体,添上Uses Pmod1à设置两个网格对象的DataSource分别为DataSource1与DataSourc2à以PM_1.Pas与ZM_1.Dpr保存其单位文件与项目文件,最后窗体界面如图所示。
三、在DbGrid(网格)控件“查询输入”
DbGrid(网格)控件是Delphi 数据库编程中使用最频繁的一个DataControls,直观方便,几乎所有数据库编程环境都提供该控件,在该控件的“列”对象上捆绑“ComboBox”以实现“查询输入”是一项最基本的工作,是任何数据库编程者都会遇到的一个问题,也是必须面对的一个问题,但就是这个问题,很多资料甚到一些“内幕”书籍上也没有明确指明,笔者为此痛苦了好久。
要透切理解“DbGrid”控件中的“查询输入”方法,必须先明白,“LookUp”字段的真实用途?LookUp字段实质上是一个“辅助”字段,在窗体运行时它将直观的数据显示一个Combobox控件中,这些直观的数据并不保存对应的数据表中,保存的是这些直观数据对应的代码。
还以前面提到的Class.db与Teacher.db为例,Class.db中的教师代号Tno的值,谁也记不准,希望在输入课程表Class.db中各项数据时,TNO字段能以“Combobox”控件的方式“直观”显示出每位教师的“姓名”,选中某位教师后,该教师的代号的值,自动送到Class.db表的Tno字段中,这就是“LookUp”字段的真实含义。
LookUp字段的建立是接收数据表(如Class.db)的Fields Editor…(字段编辑器)中进行的,具体操作细节见下。
1、 建立数据模块
新建一个项目文件àFileàNewàData Moduleà建立一个数据模块à添加如下表所示的对象à根据下表设置各对象的属性à以Dmod3.Pas存盘。
对象名 |
属性值 |
Table1 |
DataBaseName=C:\db TableName=Class.db Active=True |
DataSource1 |
DataSet=Table1 |
Table2 |
DataBaseName=C:\db TableName=Teacher.db Active=True此处切记不要设置其MasterSource、MasterFields,这与主表/明细表结构不一样,否则会出错
这就是诸多大侠们一头“雾水”的地方。 |
DataSource2 |
DataSet=Table2 |
2、在主表Table1建立查询字段CTname
在数据模块Dmod3.pas中双击数据表对象Table1à进入字段编辑器à右击先“Add All Fields”将所有字段添加字段编辑器中à再右击选“New Fields”à弹出“New Fields”图,按图示设置好有关属性,这里每个属性的含义一定准确理解。
Names:是指“主表”中建立的“查询字段”,它并不在主表中保存数据,仅起一个辅助作用,是“虚拟字段”,显示的数据为“从表”中Result Fields对应的字段的值。
KeyFields:它是“主表”中的字段,此处为TNO,可以理解为接收字段,就是它的值要用“查询输入”的方式来输入。它常常是主表中的“外码”。
DataSet:它指明“从表”的名称,我们“查询输入”时,查询的数据就是这张表中某个字段的数据。此处为Table2,即Teacher.db对应的表对象。
LookUpKeys:指明“从表”的索引字段,大多数情况下是“从表”的主键,并且与“主表”中的接收字段即“KeyFields”对应的字段同名。值得注意的是LookupKyes指明的字段,Key Fields指明的字段不同名时,这两者所指明的字段类型必须相同、含义必须相同。
Result Fields:指明在主表的查询字段(即Names所指字段)显示的数据是“从表”中哪个字段,此处为从表中的Tname字段。
以上设置过程,你也可以在该CTName的对象观察器(Object Inspector)直接进行修改,其属性名依次为KeyFields、LookUpDataSet、LookUpKeyFields、LookupResultFields,同时你也会发现其FieldKinds为fkLookup。
3、建立显示窗体
切换到主窗体à按F12进入其代码窗体,在其Implementation的下方写上Uses Dmod3à在主窗体上添加一个网格控件à 其DataSource为DataSource1à分别在Pdb.Pas单元文件保存以上窗体,以Zdb.Dpr保存其项目文件à按F9运行得到如上图所示的效果,此愿望最终实现了。不写一条语句实现了“查询输入”,真是爽极了!
在网格中实现“查询输入”最关键之处:
l 在数据模块中既要建立“查询”数据对应的表对象,但绝不能设置其MasterSource与MasterFields两属性;这是最容易犯错误的地方。
l 在主表中建立“查询字段”,仅起一个辅助作用。
l 在主窗体中只能建立主表对应的DbGrid(网格)控件,不能再建立一个从表(即查询表)对应的DbGrid(网格)控件,要不落入了“Master(主表)/Detail(明细表)”的套路中,同时可能会触发一些致命的错误,这也是最容易犯错误的地方。
四、利用DbLookUpCombobox来实现“查询输入”
方法三介绍的是“在DbGrid(网格)控件”中实现“查询输入” ,如果处理的数据的控件不是DbGrid控件,而是DbEdit控件等,这是方法三提供的方法行不通了,这时只能采用DbLookUpListBox控件或DbLookupCOmbobox控件来实现,操作过程如下:
1、 建立数据模块
新建一个项目文件àFileàNewàData Moduleà建立一个数据模块à添加如下表所示的对象à根据下表设置各对象的属性à以Dmod4.Pas存盘。
对象名 |
属性值 |
Table1 |
DataBaseName=C:\db TableName=Class.db Active=True |
DataSource1 |
DataSet=Table1 |
Table2 |
DataBaseName=C:\db TableName=Teacher.db Active=True此处切记不要设置其MasterSource、MasterFields, |
DataSource2 |
DataSet=Table2 |
2、建立主窗体
在主窗体的代码窗体之Implementation的下方à写上Uses Dmod4à在窗体上添置如图所示的控件,具体设置如下:
1. 在“Cno”右边添加DbEdit控件,其DataSource设为DataSource1;其DataFields为CNo,表示该控件用来编辑CNo字段的;
2. 似处理处理其它控件;
3. 为TNO字段设置“查询输入”方式:
l 在“TNO“右边添加DbLookUpCombobox,其DataSource为DataSource1,其DataFields为Tno;
l 最重要的是,其ListSource(显示数据源)为DataSource2,即Teacher.db对应的数据源;
l 显示字段属性ListFields为 Tname;
l KeyFields为TNo,表示提供查询数据的“从表”按此字段进行索引;
l 属性Key Fields所指的字段实际相当于“方法三”定义Lookup字段时的“Lookup Keys”所指的字段,并不相当于“方法三”定义Lookup字段时的Key Fields 所指的字段,就是因为这字面上相同,使得很多前辈在此百思不得其解!
l 基于与“方法三”中同样的理由,Key Fields(此处为Tno)所指的“从表”字段名,与DataFields(此处为Tno)所指的“主表”中“接收字段”是互相对应的,这两者所指的字段其名称一般是相同的(VB/VFP是必须相同的),在Delphi 中可以不同名,只要其数据类型、所指明的含义相同即可。
l 通过ListSource、ListFields、KeyFields 三属性,使得主表(此处为Class.db)可使用“查询输入”方式从“从表”(此处为Teacher.db)中选择性的输入数据。
1、 在窗体的下方添加一个数据导航条,其DataSource为DataSource1。
此例仅对DBLookupCombobox举了例,对于DbLookupListBox的用法是完全类似的。
五、其它方式实现“查询输入”
如果某字段的值不是来源于另一张表,而是某几个固定取值之一,这时根据具体情况使用如下方法来解决:
1、 如果“方法三”中的DbGrid对象中某列数据是从某几个固定数据中取值,那么可双击该DbGrid控件,进入“Column Propertis Editor”(列属性编辑器)选中该列,然后在其PickList属性输入这几个固定值。
2、 如果“方法四”中某个DbEdit对象的数据,为某些固定值中的一个,则可用DbListBox或DbCombobox两控件,在其Items属性中输入这几个固定值即可。
3、 也可以动态修改“列”对象的PickList属性或者DbListBox的Items属性,以实现将其它表中的字段做为原始数据,实现“查询输入”,这可能是最灵活的方式,但是消耗的资源会受点影响,速度会慢一点。
六、总结
本文从DataBase Desktop(数据库桌面)、Master(主要)/Detail(明细)控件、DbGrid(数据库网格)对象、dbLookupListBox(数据库查询列表框)与DbLookupCombobox(数据库查询组合框)等五个方面,较系统的的介绍了各种“查询输入”方法的具体实现细节,不与一行代码就实现了“查询输入”,这大概也是Delphi 的独到之处。
最后请注意在不同的实现方法中,彼此细微的区别是最关键的,千万不要出现“知识串户”的现象。
|