[推荐]delphi基础学堂-详细讲解delphi
荐 ★★★★★
delphi基础学堂-详细讲解delphi
一、基础补充
1 文件类型
我们使用TStringList虽然能完成简单的文本文件操作,但很不灵活,比如文件很大,比如我们只想读文件前两行,并不需要所有的数据。这就需要使用文件类型。
【例】打开文本文件,读前两行到memo中。
var f: TextFile; s:string; ... AssignFile(f,'c:\a.txt'); reset(f);
readln(s); memo1.lines.add(s); readln(s); memo1.lines.add(s);
closefile(f);
◇TextFile是delphi中预定义的文件类型。
◇写到文件中,与上面的方法类似。只不过是 reset改为rewrite,readln改为writeln。
◇AssignFile只是把文件变量和某个名字联系起来,如果文件不存在,并不出错。
2 二进制文件的读写。
二进制文件的操作有很多方法,比如使用delphi提供文件管理函数;使用windows提供的API函数。有一种与操作系统无关的方法,就是使用流的方法,即TFileSteam类。
TFileStream是从TStream继承的。TStream是抽象的基类,表示着公共的流的特征。
流是为了在线性地址编码的设备中存储对象而设计的。当对象的数据模型被确定以后,就需要一种表示方法,把这种结构在线性的地址空间中表达出来,比如内存,比如硬盘。这个过程叫流化,串行化或序列化。一个不针对任何介质的抽象流类应具备的特征是:总长度;提供线性地址中的读写能力。因而应该有当前位置指针;读方法和写方法。
TStream的设计提供这些属性和方法。size:总长度。 position:当前指针位置。read,write。
TFileStream代表文件流。允许我们向文件的指定位置写入或读出对象。这些对象包括简单的类型,如整数,字符等,也包括用户定义的复杂的记录或自定义对象。
◇TFileStream对象也象其他任何对象一样,在使用前要申请,在使用后要释放。
【例】创建二进制数据,向其中写如一个整数,一个字符串,一个表示学生的记录。
var t: TFileStream; ... t := TFileStream.create('c:\a.dat', ...);
try t.write(12,4); t.write(buf, sizeof(s)+1); t.write(stu1, sizeof(STU));
finally t.free; end;
◇string类型是长串类型,在堆中分配内存。不能直接写到文件中,要转换成字符数组。
◇C语言串与pascal格式串的区别。为什么在sizeof()后边要加1?
◇使用TStream对象的时候,并不需要打开文件和关闭文件。create的时候,可以选择许多参数,来决定以什么方式打开一个文件。只读?只写?如果存在怎么办?与其他人共享吗?
使用TTable控件虽然能对表进行自由地操作,但当需要从多个表中取数据的时候,就显得无能为力了。delphi提供了TQuery控件,封装了应用十分广泛的SQL查询方法。
二、SQL介绍
1 SQL是结构化查询的英文缩写。SQL方法几乎被所有的数据库所支持,尤其是大型数据库。SQL是函数式的语言,它的特点是:只提出要求,不描述执行的具体过程。
◇回忆 foxpro的方法,use xx; go top; skip 1 ...怎么用索引 怎么找 相当复杂。
2 SQL的数学基础是集合论。它实际上就是关系运算的描述。目前的国际标准是SQL92。SQL99
将是新的标准。SQL虽然叫结构化查询语言,但实际上它可以执行许多对数据库的操作,不仅仅是查询功能。当然查询是它的主要功能,也是内容最丰富的部分。
3 SQL提供了对不同数据库的统一访问方法。使数据库应用程序在不同的数据库之间进行移植变得容易。大型库一般都在SQL92的基础上进行了扩充。如果对可移植性要求很高,则尽量使用SQL92的标准。少用存贮过程和触发器。
3 SQL的简明语法:
DDL (Data Defination Language) 数据定义语言
create table 表名(字段名 类型,字段名 类型,...) //创建表
例:create table "stu.dbf"(s_name char(10), s_age numeric(10,2), s_addr char(40))
◇当表名包含SQL语法关键字时,要用引号引起来。
◇SQL语句可以写在一行,也可以分成多行。
drop table 表名 //删除表
alter table 表名 add 字段名 类型,... //修改表
alter table 表名 drop 字段名,...
例:alter table "stu.dbf" add s_class char(5)
create index 索引名 on 表名(字段1,...) //创建索引
例:create index sid on "stu.dbf"(s_name)
drop index 表名.索引名
DML (Data Manipulation Language) 数据操纵语言
insert into 表名(字段1,字段2,...) values (值1,值2,...) //添加数据
例:insert into "stu.dbf"(s_name, s_age, s_addr) values('wang',12,'bei jing')
update 表名 set 字段名=值,... where 条件 //修改记录
例:update "stu.dbf" set s_age=15, s_addr='tian jin' where s_name = 'wang'
delete from 表名 where 条件 //删除记录
select 字段名或表达式1,... from 表名1 [as 别名1], ... [where 条件]
[order by 字段1,...] [group by 字段 ...] //查询语句
例:①select * from "stu.dbf"
②select s_name s_age from "stu.dbf"
where s_age > 20 and s_addr like "beijing%"
order by s_name
③select A.s_name B.score from "stu.dbf" as A, "score.dbf" as B
where A.s_name = B.s_name
④select count(*), sum(score) from "score.dbf" group by s_name
◇like表示模糊匹配,只要符合串中提供的样式即认为匹配。
◇从多个表中查询的时候,实际上是先执行表的笛卡尔积,然后进行行选和列选。
◇SQL92只支持很少的运算函数:sum求和, avg求平均,max最大值,min最小值,count求记录的个数。大型数据库中,扩展了很多自己的函数,尤其是对字符串和日期类型的操作,需要时参考相应数据库的有关文档。
◇group by主要是为了分组进行某种统计
二、使用TQuery对象
与TTable相同,TQuery也是从TDataSet继承来的,因而在其中可以使用TDataSet提供的导航和数据操纵方法。与TTable不同的是,TQuery不是去指定一个表名,而是代表了通过SQL语句返回的数据集,可以把它看成一张虚拟的表。此外,TQuery还可以用于去执行不返回结果集的操作命令,就是除了select 以外的SQL语句。
【例】使用TQuery创建学生表,设定索引,并添加记录。
三、关于多用户访问
1 大型库中都提供了事务的方法,来保证对数据操作的完整性。对一次操作分两个阶段提交给服务器。先提交操作的内容,然后只用一个指令,表明上面的操作是确认,还是回滚。
2 访问同一数据造成的冲突。
①准备修改数据项A的过程中,A已经被其他用户所改变。这样造成了对先前修改的覆盖。
②类似地,要修改的数据项A可能已经被其他用户删除。
③读取和修改某用户正在修改,但尚未确认的数据,可能被该用户回滚所淹没。
3 大型库中都提供了叫做隔离级别的机制,来控制怎样对待共享的数据。delphi中可以设置为dirtyRead, readCommitted,repeatableRead。许多数据库并不支持所有这些隔离级别。
4 为控制多用户的访问,锁的方法被广泛使用。从范围上看,可分为表锁,页锁和记录锁。从兼容关系看,可分为读锁(兼容锁)和写锁(排斥锁)。
5 如果有多个用户需要访问多个表,就有可能产生锁的循环等待,叫死锁。很多数据库设计死锁检测的功能。在用户端解决死锁的有效方法是:①需要访问多个表的时候,按照字母顺序进行访问。②当对同一个表既读又写的时候,先实施写的操作。
◇怎么写?在没读的时候不知道写什么。可以进行“假写”:update xxx set f1=f1 where ...目的只是为了先获得写锁。
6 delphi中自动游标的使用有潜在的危险,缺省方式会把未读的记录全部锁住。解决的办法是:①调用TDataSet的fetchAll方法,把所有的记录取回到本地。②当数据量十分大的时候,一般大型库都提供了额外的SQL语句,可以控制结果集返回的最大记录数。③也可以启用脏读方式,需要注意的是,许多库并不真正支持脏读模式。④使用缓冲模式,其效果相当于使用fetchAll。
7 怎样实现数据变更时通知?一般的方法是主动查询。为避免对多表的频繁查询,可以在关心的表产生变化时,通过编写触发器在一个监视表中记录变化及时间戳。
四、DBGrid的定制
1 设定DBGrid的options属性,可以限定很多界面效果。常用的:
dgEditing 是否可以通过DBGrid修改数据集。
dgColumnResize 用户是否可以用鼠标拖动列来改变宽度。
dgConfirmDelete 在删除数据的时候,是否要弹出一个确认对话框。
2 如果使用永久字段,可以在设计时编辑许多显示属性。方法是双击DBGrid|Add All Fields把所有的列都选入。然后选择某一列,在对象浏览器中改变它的属性。常用的有:
color 设定列的显示底色 readOnly 是否为只读列
title.caption 标题内容 title.color, title.font.color 标题底色,字色
visible 是否可见(要隐藏吗)
width 显示宽度,单位是象素,注意与TField.displayWidth的区别。
pickList 是TStrings类型对象。可以构造一个列表,运行时能通过下拉列表提供数据。
◇所有设计阶段的设置都可以通过写程序的方法,在运行阶段实现。
【例】通过程序的方法设定列的颜色,标题,宽度,并提供下拉列表。
3 我们以上看到的是改变某一列的所有数据的显示特征。如果要求根据记录的值来确定显示特征,就无法使用上边的方法了。比如使用不同的颜色来显示数据。我们可以通过为DBGrid的事件的
onDrawColumnCell编写代码来控制输出的内容。
【例】定制DBGrid使大于20的数值用红色显示。
◇为了实现自定义输出,一定要先设定DBGrid的defaultDrawing属性为false。
◇通常情况下,总是要调用原来的输出方法:DefaultDrawColumnCell。该方法的参数与事件对应的方法只有微小区别,就是它不含sender参数。
五、截住TField的事件,实现动态控制
如果有这样的要求:把数字列表示成汉语的大写数字,该如何处理?当然可以通过写onDrawColumnCell事件来实现。但当这种显示方式被用在多个控件显示同一数据的时候,最好能让TField提供用于显示的文本。这可以通过拦截TField的onGetText事件来实现。
【例】为onGetText写代码,把V值输出为大写表示。
在TForm的定义中添加如下过程: procedure myGet(Sender: TField; var Text: String; DisplayText: Boolean),并实现它:
if sender.asInteger = 1 then text := '一';
if sender.asInteger = 2 then text := '二'; .......
然后,通过一个事件,把myGet连接到TField的onGetText事件上(事件其实就是函数指针)
table1.fileds[2].onGetText := myGet;
◇onGetText在显示控件每次需要数值的时候被调用。布尔量表示当前是不是处在编辑的状态。
文章录入:cainiaowang 责任编辑:cainiaowang