[推荐]delphi基础学堂-详细讲解delphi
荐 ★★★★★
delphi基础学堂-详细讲解delphi
一、基础补充
1 变体类型 variant
变体类型就是其数据类型在运行期间允许发生变化的类型。
定义: var v: variant; //定义后其值为:unassigned
◇unassigned与NULL是有区别的。NULL表示该值未知,unassigned表示未赋值。
◇variant类型在赋值和运算的时候,系统自动实施类型转换。
【例】赋值和判断类型
2 变体数组 可以包含不同的数据类型元素的数组。
定义:var a: variant; a := VarArrayCreate([0,9],varVariant);
a := VarArrayof([1,'myname',12.4]);
◇数组类型仍然是variant。
◇可变数组允许它的元素是不同的类型。因为实际上它们都被转换成统一的variant类型。
二、使用别名
1 使用别名的好处是方便数据库的移植。
2 别名是一个名字,一个字符串。它代表了一组与数据库连接有关的设置。比如驱动程序名,数据库名,连接参数等等。
3 可通过delphi附带的配置工具来配置别名。配置的目的就是生成一个配置文件。
4 在ODBC数据源中添加的ODBC配置会自动反映在BDE别名配置中
【例】配置一个dbase表的别名,并通过它打开表。
开始|程序|borland6|BDE Administrator 启动配置程序。选databases页,在databases上鼠标右键|new..., driver name中选STANDARD,按OK。在左边起一个名字作为别名,在右边,default driver 选dbase,path中填写希望dbase表所在的目录。存盘,退出。
◇一般来说,别名代表一个数据库。在dbase系统中,数据库就是一个目录;对Access,数据库则是一个独立的文件,所有的表都存在这个文件中;对有些大型库,数据库表现为硬盘分区,无法直接看到;甚至有的数据库是按自己定义的方式存在于整个硬盘上。
三、连接多种类型的数据库
1 通过ODBC连接Access
在控制面板中找到“数据源(ODBC)”,双击打开;选系统DSN页;选添加;选microsoft Access driver (*.mdb);按完成;给数据源起个名字,就是要生成的别名;选“选择”或“创建”,来指定一个Access数据库;按确定。
◇在ODBC中配置的数据源会自动地作为别名添加在BDE Administrator中。
◇有时,在delphi程序打开的时候,刚刚配置的ODBC无法立刻反映在控件中,只要先关闭,在重新启动delphi即可看到新添的别名。
2 通过ODBC连接SQL-Server
基本步骤与连接Access相同。只是driver要选SQL Server,服务器如在本机可以选(local),登陆方式可以是选NT登陆(不需要用户名和密码)或用户登陆(必须知道用户名和密码),下一步,选中“更改默认数据库”,通过下拉列表选一个数据库,以下都确认即可。
◇有时,在服务器下拉列表中没有反映(沙漏光标),可以直接手填服务器的名字(单击任务栏上的服务器图标会看到本机服务器的名字)。
◇建议在最后确认前,使用“测试数据源”检查一下是否配置正确。
◇有时,使用用户登陆方式,密码和用户名都正确,但就是连接不上。这可能是因为在SQL Server中设置了只允许NT登陆方式造成的。改变的方法是:启动SQL Server企业管理器,选要操作的服务器,鼠标右键|属性,选Security页,把Authentication项选在“Sql server and windows”上。
3 通过ADO连接Access
在ADO页上,把ADOConnection控件放在Form上,双击打开|按build,选microsoft Jet 4.0 OLE DB ...,下一步,选数据库名字,连接测试,确认。放ADOTable在Form上,connection属性指向ADOConnection,选择表名等。其他操作与Table类似。
◇ADOConnection的配置过程实质上是形成一个串,赋给它的connectionString属性。
◇如果不希望每次都弹出一个密码对话框,可以在配置过程中指定密码,然后把它的loginPromt属性改为false。
◇实际上,我们完全可以不通过配置过程,直接在connectString中填写适当内容来完成上述的工作。也可以把配置存在一个文件里,启动时程序时从那个文件中读入。
4 通过SQL-Link连接SQL-Server
SQL-Link是borland公司提供的连接大型数据库的方法。这种方法比使用ODBC要快。
启动BDE Administrator,新建一个别名,选MSSQL,确认。左边起名字;右边需要修改三项:databaseName:Sql server 上已经存在的数据库的名字;host name:服务器所在的主机的名字(如果是本机,此项可空);server name:服务器的名字。
◇虽然使用SQL-Link,在本机上仍然要安装大型库的客护端软件。
◇如果要屏蔽密码输入框,需要在form上放TDataBase控件。把它的loginPrompt设为false,填写它的params属性:user name=XXXX, password=XXXX
四、使用TDataBase
1 TDatabase代表了一个数据库。
多个TTable, TQuery等代表数据集的控件可以指向数据库控件。我们在没有使用TDatabase控件的时候也完成了数据库的操作是因为,系统替我们使用了一个默认的TDatabase对象。
◇注意,指向TDatabase的方法与在数据敏感控件中使用的方法不一样。先为TDatabase控件选择一个别名,再为它的DatabaseName起一个名字。其他数据集控件中的DataName一项要填写刚刚起的那个DatabaseName名字,而不是TDatabase控件的名字(一般为database1)。
2 可以使用它自动传递用户名和密码,而不弹出登录提示框。
database1.loginPrompt:=false;
database1.params.clear;
database1.params.add('user name=sa');
database1.params.add('password=abcd');
◇注意user name的拼写,中间有一个空格。名字和密码都不使用引号。
3 通过TDataBase使用显式定义的事务功能。
database1.StartTransaction;
try 进行多次数据库的操作; database1.Commit;
except database1.Rollback;end;
◇在没有显式地使用事务操作的时候,相当于每一个SQL语句是一个独立的事务。
◇一般来说,一定要使用try..except..end的结构来防止一个事务开始后,没有后续的动作。很多大型库并不会自动地取消一个事务,即便它在一周前就开始了。悬浮的事务会一直锁住某些表,使其他用户的操作无法进行。
4 通过它,可以在不打开表的情况下,取得库中所有的表名,以及指定表的所有字段的名字。
database1.GetTableNames(memo1.lines);
这一命令会把当前库中的所有表的名字写在一个memo中。
database1.GetFieldNames用来取得指定的表中的所有字段名,用法与上边类似。
5 通过它,可以直接执行SQL语句。
database1.Execute('update stu set name="aaa" where ...');
五、再谈多表联合查询
1 多表联合的实质是集合的笛卡儿积运算。
2 随着联合的表的数目的增加,积的记录数目呈指数式增长。虽然大型数据库在这方面作了大量的优化工作,多表联合仍然十分耗费服务器的资源(时间和空间)。
3 “代码-描述名”的定义方式有很多优点,因而是数据库设计时广泛采用的方案。但在查询的时候,不可避免地用到多表联合。在多表查询的时候,只要其中一个表的记录数目很大,很可能会影响查询的性能。
4 解决的方法:①当发现查询性能下降的时候,就要建立临时表,通过多步进行查询。仅仅通过建立视图的方法不能解决性能的问题。因为视图不是真的表,数据库中只保存了视图定义。
②当“代码-描述”表较小的时候,用多表联合十分不和算,我们可以把这些表先读到本地,再通过动态的翻译的方法实现最终的显示效果。
【例】使用动态翻译的例子。对性别和班级进行动态翻译。
实际上就是前边onGetText技巧的翻版。我们先打开代码对照表,读到本地一个TStringList中,然后在myGet过程里,通过查找TStringList来动态地提供text的值。
5 多表联合是数学基础是集合论,它的功能十分强大。实际上,只要是表中存在的数据,无论要求怎样的输出结果,总能通过SQL语句来实现。有的时候,我们需要用到一个表和它自己的联合来解决一些特殊的问题。
【例】求出一个表中某列数据有重复值的所有项(下表为横向排列)
K 1 2 3 4 5 6 8 9 34
V 2 2 3 5 6 6 7 9 10
结果应为: k 1 2 5 6
分析这类问题的方法是先写出笛卡儿积的所有行,再选择需要的行,看它们有什么特征。
再看类似的例子:
【例】求上面表中K值不连续的项(只找向上不连续即可)
结果: K 1 8 34
六、报表的使用
1 使用QuickReport粗略地打印报表
QuickReport并非borland公司的产品。其设计很粗糙,功能很难适应中国报表。
先在form中放QuickRep控件,代表一张纸。放入若干Band代表数据区。可以改变bandtype来指定band的类型。要与数据相连需放入数据集控件,把QuickRep的dataset属性指向该控件。
可以用鼠标右键|preview来预览报表。
◇表格线需要放图形控件实现。band的边框线控制不准确。
◇用鼠标拖动的方式几乎很难完成对齐工作。需要直接调节属性,或在程序中设置。
2 使用F1Book控件完成复杂报表输出
F1book功能十分强大,几乎就是电子表格的翻版。如果用过Excel则极易上手。
在ActiveX页中找到F1book,放在form上。鼠标右键|workbook Designer 可以可视化地设计表格的属性(和Excel的功能很类似)。
单元格的表示法:A1表示一个单元,A1:C1表示一行单元格,A1:C10表示一片单元格。
当前的活动单元:.col .row
当输入字符串的时候,自动左对齐;当输入数字的时候,自动右对齐。怎样输入一个数字,并把它看作是字符串呢?输入时,用'123就可以了。
可以指定某个单元为计算值。方法是:=sum(A1:C10)以等号开始一个函数
所有在设计阶段的功能都能用代码的方式完成。
F1book提供数百个方法可共调用,滋举其要:
给一个单元格赋字符串值 f.textRC[row,col] := 'abcd';
给一个单元格赋数字值 f.numberRC[row,col] := 123;
设置需要打印的区域: f.printArea := 'A2:F15';
重新计算所有计算字段: f.Recalc;
f.printHCenter := true; 水平居中 f.printVCenter .. 垂直
f.printLandscape := true; 横向打印
f.prinLeftMargin,f.printfRightMargin 左右边距
f.setPrintScale(nScale, bFittopage, nVPages, nHPages);
nScale: 10-400 放大率 100 表示原样大小
bFitToPage: true 满纸打印(不一定满一张纸,而是可以满一组纸)
nVPages: 垂直纸页数 nHPages: 水平...
f.FilePrint(true); 打印输出。显示对话框否?
◇缺少打印预览的功能。
3 完全自己控制打印
TCanvas对象封装了windows的绘图环境,可以在抽象的设备上进行绘图。
在打印机上绘图:
printer是全局对象,代表当前的打印机。 printer.canvas是TCanvas对象,代表打印机的绘图环境。
printer.pageHeight,printer.pageWidth 代表纸高和宽,单位是象素。
TCanvas 内含了许多有用的对象
pen: TPen 笔对象,用来画线或其他图形
brush: TBrush 用来填充颜色
font: TFont 用来设置字体的特征
【例】在form的canvas上输出的例子
canvas.pen.color := clRed; canvas.pen.width := 2;
canvas.moveTo(10,10); canvas.lineTo(100,100);
canvas.brush.color := RGB(10,20,100);
canvas.rectangle(20,20,250,100);
◇在默认的情况下,canvas输出的计量单位是象素。使用这种方式存在一个问题,就是打印机的分辨率一般比屏幕要高出许多倍,同样的语句,在打印机上可能就变成了“缩微图象”。怎样实现自由缩放?这涉及到windows下的设备映射方式问题。Windows提供多种设备映射方式,缺省的方式是:MM_TEXT,即象素映射方式。
【例】改变缺省的映射方式,实现设图形的整体放缩。
setMapMode(canvas.handle,MM_ANISOTROPICD); //不等轴映射
setWindowExtex(canvas.handle,1000,1000,nil);
setViewportExtex(canvas.handle,200,200,nil);
.... // 绘图过程
setMapMode(canvas.handle, MM_TEXT); //恢复原来的模式
◇canvas是对windows绘图场境的封装,设备场境是易失资源,所以对canvas的设定和操作要在一个紧凑的代码中完成,而不能期望其设置的持久性。
我们在form中输出时,为了把输出限制在一个矩形区域内,可以使用控件来完成(比如system 页中的TPaintBox),但对打印机的输出却不能使用控件,怎样把输出限定在一个区域中呢?可以利用windows中提供的剪切区的功能来实现。
【例】使用剪切区控制输出的范围
var myR: HRgn; //剪切区对象句柄
myR := creaetRectRgn(50,50,300,300); // 创建剪切区
selectClipRgn(printer.canvas.handle, myR);
.... // 绘图操作
selectClipRgn(printer.canvas.handle, 0); //使用原来的剪切区
deleteObject(myR); // 删除对象
◇与绘图有关的很多对象都是系统的敏感资源,我们应当遵循如下规则:
①使用的时候才申请,而不是储备待用。
②不用的时候立即释放。
文章录入:cainiaowang 责任编辑:cainiaowang