代码编写人员都有过这样的经历:往往在一个小小的问题上卡壳,一耗就是几个小时,甚至几天。待问题解决后才发现,其实这些问题大都非常简单,有时是一个知识点的疏忽,有时只须“玩”几个小技巧而已。笔者在 Delphi 数据库编程的实践中摸索出了一些小经验,愿与大家共享(数据库以 Access 为例)。
1,数据表的主关键字索引问题:这个问题的直接表现就是数据集的 post 方法不能把记录数据保存到表里去,系统提示“不能定位记录位置”等一些信息。这个问题笔者曾经遇到过,也在论坛上见网友发帖问过,可见是一个普遍性的问题。而且这个问题还比较隐蔽,我们不太容易想到保存记录和索引有什么关系。实际上,post 方法的背后,执行数据添加、更新、删除的还是标准的 SQL 语句,如果 SQL 语句不能确定将要操作哪条记录,就会给出出错提示。问题的解决办法是,给表建立一个类型为“自动编号”的字段,并设为“主关键字索引”。这个字段在程序中用不用都可以,但如果用 DataSet 与该表连接,则 DataSet.CommandText 的 Select 语句中必须包含该字段。
2,数据集 Dataset 的导入导出:Dataset 有方法 SaveToFile 和 LoadFromFile 用于把表导出为普通文件,然后再还原回来。这两个方法对于数据的传递非常有用。但是在使用中发现,数据还原时,在将数据从文件中装载到数据集后,使用 post 方法,与数据集绑定的表并不自动更新!怎么办?只好借助 SQL 语句了:假设表中有两个字符型字段 bm 和 dlzl,添加一个数据集控件 ADODataSetTmp 和命令控件 ADOCommand ,然后参考以下代码:
// 保存 Dataset:
ADODataSet1.SaveToFile(Extractfilepath(application.exename)+'测试.txt');
// 把 SaveToFile 生成的数据用 loadfromfile 导入到表中:
ADODataSetTmp.LoadFromFile(Extractfilepath(application.exename)+'测试.txt');
ADODataSetTmp.First;
while not ADODataSetTmp.Eof do
begin
Fld1 :=ADODataSetTmp.FieldByName('bm').AsString;
Fld2 :=ADODataSetTmp.FieldByName('dlzl').AsString;
ADOCommand1.CommandText :='insert into RoadType (bm,dlzl) values('+''''+Fld1+''''+','+''''+Fld2+''''+')';
ADOCommand1.Execute;
ADODataSetTmp.Next;
end;
3,保存“时:分”格式的时间:保存时间当然要用“日期时间”类型的字段了,这是我们最容易想到的。但是对于“时:分”格式的时间,用“字符”型字段来保存可能更方便一些。当然,保存前要先构造“时:分”格式的时间值:
var
H,M,s,ms: word;
mm: string;
begin
DecodeTime(DateTimePicker1.Time, H, M, s, ms); //DateTimePicker1是日期时间控件
mm :=trim(IntToStr(M));
if length(mm)=1 then mm :='0'+ mm;
DBEditTime.Text :=IntToStr(H)+':'+ mm; //DBEditTime与“时:分”格式字段绑定
end;
4,修改表结构应注意的问题:假设数据集 Dataset1 对应于表 Table1,且在设计阶段处于激活状态。那么,当你删除了表中的某些字段或是修改了某字段的数据类型时,你的程序代码可能就打不开了,现象是 Delphi 在打开工程文件时异常退出,且没有任何提示信息。这种错误也比较隐蔽,会让初学者感到莫名其妙。正确的做法是,关闭数据集,修改表结构,然后再打开数据集。
表中的字段长度修改后,Dataset 的字段如果出现异常,最好删掉重 add 一下。
5,Dataset 的刷新问题:如果对 Dataset1 中的记录进行增、删、改等操作后,与之关联的 DBgrid 不刷新,则可以连续执行 Dataset1.Active:=false; Dataset1.Active:=true; 两句代码强行对 Dataset1 进行刷新。
6,DBText 和 DBEdit 用法的异同:首先,它们的外观是不同的,DBEdit 与 Edit 文本控件外观完全一样,而 DBText 则更像标签 Lable 控件。它们都可以绑定数据库的某个字段,但 DBText 不能编辑文本。如果你通过程序代码控制数据的自动填写,则一定要使用 DBText 控件,代码是 DBText1.Field.AsString :='文本值';,如果用 DBEdit 控件,当用鼠标点击后,表中字段现有的值就会改写用程序代码所赋的值。
7,Listbox、ComboBox 等选项的取消:列表框等控件中的内容,选中后就再去不掉了。其实可以用程序代码实现,Listbox 用 ListBox1.ItemIndex :=-1,ComboBox 用 ComboBox1.ItemIndex :=-1。而对于 DBLookupComboBox 控件,删掉表中对应字段的值,就可以清空其中的显示。
8,SQL 语句中的“年”“月”问题:Delphi 的 SQL 语句中可以应用 Year()、month() 等函数。但是注意:year() 函数的返回值为 4 位纪年,即只能和 4 位数的“年”(如 2001,1999)比较;month() 函数返回的月份形式为 1,2,3……10,11,12等,它不能与 01,02,03 …… 09 等形式的月份进行比较。
9,SQL 语句中变量(字符串型、数字型、日期型)的应用:SQL 语句中也可以应用变量,假设变量 s、n、d 的类型分别是字符串、浮点数和日期,则类似的 SQL 语句如下:
'select * from table where fld1=' + '''' + s + ''''
' and fld2=' + FloatToStr(n) +
' and fld3=' + DateToStr(d) + '';
10,让值为 0 的字段在报表中显示为空:打印报表时,值为 0 的字段不打印,会使表格清晰、美观。我们可以在报表控件的 DetailBandBeforePrint 事件中对报表进行过滤,参考代码如下:(QRDBText1 用于显示字段值,TQRMDFormRoadDoc 是报表控件所在的窗体名)
procedure TQRMDFormRoadDoc.DetailBand1BeforePrint(Sender:TQRCustomBand;var PrintBand:Boolean);
begin
if Mainwindow.ADODataSet1.FieldByName('length').AsFloat=0 then
QRDBText1.Enabled :=False
else
QRDBText1.Enabled :=True;
end;
11,QR 报表中让 QrLable 标签中的文本垂直排列:QrLable 标签用于在报表中显示表头等文本信息。它的 WordWrap 属性默认为 True,但是当文本横向超长时它就是不“拐弯”!笔者在一次意外的实验中发现,如果在其中的字符串的某个字符后加一个空格,字符串就会从这里折行。所以,如果在每个字符后加一个空格,那么字符串就会垂直排列了。
12,QR 报表表头数学公式的构造: 表头中的计量单位(如平方米)有时必须用数学公式中的形式表示。如果比较复杂,可以考虑使用图片等形式,如果较简单,如平方米,则可以使用 QRLable 控件,通过调节字号大小和它们的相对位置来构造。
13,用代码控制针式打印机自动联机:可以用 Delphi 调用汇编代码来实现针式打印机的自动联机:
Procedure AutoLinkPrt()
begin
asm
mov dx,0h; //LPT1
mov ah,01h;
int 17h; //打印中断
end;
end;
14,给程序建立一个“公共模块”:为了对我们自己构造的自定义函数进行集中管理,以及便于代码重用和移植,把这些代码放在一个“公共模块”中是一个不错的注意。方法是,“新建”一个 Unit,在其中放置我们的代码,如果哪个 Form 需要调用这些函数,在 implementation 后 uses 一下它就可以了。
15,注意 Form 生成和关闭时的事件次序:Form 在生成和关闭时会触发一系列的事件,了解它们的次序对编程是有绝对的好处的。
Form 产生的过程中, 各事件发生与执行的次序,如果是一般的 SDI(单文档)窗体, 各事件的发生次序如下:
OnCreate
OnShow //在屏幕上看到这个视窗
OnActivate //激活
OnPaint //此时定制控件的外观
窗体外观的控制,要在窗体的 OnPain 事件中,对 Dataset 等数据控件的控制,要在窗体的 OnActive 事件中;
Form 关闭时事件响应的先后顺序是:
CloseQuery
Close
Deactivate
Hide
Destroy
西安市雁塔区慈恩路南段 8 号电达公司 710061
张庆 zhangking@263.net 029-5213755, 13892819730
http://100000.home.sohu.com QQ:9365822 2001.11.10
|
|