[推荐]delphi基础学堂-详细讲解delphi
荐 ★★★★★
delphi基础学堂-详细讲解delphi
【思考】假如我们要把一个地图数据装入数组,然后显示它,却不知道地图数据有多大,怎么办呢?开一个足够大的数组吗?windows的消息结构只能容纳8个字节,我怎么通过这么少的字节传递长达500k的数据呢?
一、语法进阶
1 动态数组。动态数组是指尺寸在运行时可以改变的数组。
定义:var a: array of integer; //其中没有说明尺寸
◇动态数组在使用的时候,要先设定尺寸。setLength(a,20);
◇下标的引用从0开始。
◇动态数组可以当作函数的参数来传递,这种参数称为开发数组参数。对开放数组参数赋给常量的时候,使用方括号。
【例】 使用开放数组求和
function MySum(a: array of integer): integer
var i: integer;
begin result := 0;
for i:=low(a) to high(a) do result := result + a[i];
end;
.... edit1.text := intToStr(MySum([1,2,3,4]));
.... var s: array of integer; .... s[0]:=1; s[1]:=2; ..... edit1.text := intToStr(MySum(s));
2 多维数组。多维数组只不过是关于数组的数组,就是说数组的元素仍然是另一个数组。
定义:type 类型标识: array [下标范围] of array [下标范围] of 某类型;
例如:type AAA: array [0..9] of array [5..10] of integer;
访问方法:var a: AAA; ... a[1][5] := 10;
◇还有另一种定义和引用的方法,但不能体现多维数组的本质。
type AAA: array[0..9,5..10] of integer;... a[1,5]:=12;
3 函数,过程和参数
delphi中的子程序有函数和过程的区分。带有返回值的叫函数,没有返回值的叫过程。它们的定义采用了不同关键字,这是与C语言不同的地方。
定义:function 函数名(函数参数):返回值类型;
例如:function myAdd(x,y: integer): integer;
procedure 过程名(过程参数);
例如:procedure MyProc(s: string);
◇当没有参数的时候,一对圆括号要省略。这与C不同。
◇调用子程序的那个程序叫主调方;被调用的子程序叫被调方。主调方传入给子程序的作为子程序的参数的量称为实际参数,简称实参;在子程序中定义的参数,称为形式参数,简称形参。
◇delphi中子程序的参数有两中传递方式:按数值传递和按地址传递。按数值传递就是把主调函数传入的值(即实参)拷贝一份给子程序。这样子程序对这个拷贝进行修改的时候不会影响实参。按地址传送,是把实参所在的内存的地址传给子程序,子程序通过地址对数据进行的修改实际上就是在修改实参的值。
◇缺省的方式按值传递。
◇要求传地址时,使用var修饰形参。
◇有两个按地址传送的变种,限定了数值的传送方向。const 修饰的参数按地址传送,但在子程序中不能修改。out修饰的参数表明只是用于传送返回值的。
【例】 使用开放数组求和,通过参数返回和
procedure MySum(const a: array of integer; b: integer);
var i: integer;
begin b := 0;
for i:=low(a) to high(a) do b := b + a[i];
end;
◇注意,这里的const并不是说要传入常量参数,而是说传入的数据不能被修改。
4 指针
◇指针就是一个数值。这个数值是内存的地址标号。在该地址中存着某种类型的量。
定义:type 类型名=^类型名;
例子:type MP=^integer; //定义了指向整型量的指针。
使用:var p: MP; a: integer; ... p := @a; p^=5;
◇@是取得变量地址的操作。^在前定义指针;^在后取某个指针所指向的值。
运算:Inc(p);指针移动,使它指向下一个数据元素;Dec(p);指针向前移动。
◇指针具有灵活性,常配合数组一起使用。
5 过程类型
一般来说,在编译后,子程序的地址都是一个固定的数字。但有时候我们需要浮动地调用同一类子程序中的某一个,这就需要一个指向子程序所在地址而不是变量所在地址的指针。在delphi中,把这种类型的变量独立出来,叫做过程类型。
定义: type 标识符 = function(参数):返回; 或
type标识符 = procedure(参数); //注意,这种定义,没有写子程序的名字
更常用的是,指向类的方法的指针。起定义类似:
type标识符 = procedure(参数) of object;
【例】用程序的方法生成一个按钮,把这个按钮的点击事件连接到自己预先定义的成员方法中。
◇方法指针不一定要指向自己定义的类中的方法。这种设计使得我们可以不生成新的类,就改变对象对事件的响应行为。
二、熟练使用代码编辑器
代码编辑器为我们提供了许多方便的功能,能够大大地提高我们的
编程效率。许多功能都对应着快键的操作,通过熟练地使用键盘,可以事半功倍地完成许多常见的代码编辑任务。
1 追踪一个标识符的定义。鼠标右键|选find declaration
2 在当前工作的地方快速地设置或取消书签。 Ctrl + Shift + 数字
移动到某个书签。 Ctrl + 数字
3 选中某一个块。 shift + 方向键
4 把一个块向前移动或向后缩进。Ctrl + K,I; Ctrl + K,U
5 在函数的定义和实现间进行跳转。 Ctrl + Shift + 上下箭头
6 从摸板中粘帖代码。 Ctrl + J
7 向摸板中增加代码。 tools|editor options|code insight|add
8 代码补全功能。我们定义好了类的声明部分,如果语法正确,可以delphi替我们把实现部分的代码框架写好。 Ctrl + Shift + C
9 查看活动窗口列表。 Alt + 0
10 快速弹出对象监视器。 F11
11 在代码和窗体间切换。 F12
12 删除当前行。 Ctrl + Y
13 立即存盘。 Ctrl + S
14 程序复位。 Ctrl + F2
15 运行程序。 F9
16 恢复一步操作。 Ctrl + Z
三、TStrings对象
TStrnigs代表着字符串的列表,在delphi中有着十分广泛的用途。
1 TStrings是抽象类型的对象,不能生成实例。
2 我们经常用到的该类的派生是TMemo.lines属性。我们通过对Tmemo.lines的操作,就可以改变memo中的内容。
【例】用一个时钟触发事件,向memo1中添加数据。当memo1中字符串数量很多时,把第一行删除,如此往复。
memo1.lines.add(timeToStr(now));
if memo1.lines.count > 10 then memo1.lines.delete(0);
◇我们把第一行删除后,总的行数就减少了,并且其后的每一行的行号都发生了变化。
3 TStrings类的其它的常用方法。
.clear //清除字符串列表
.insert(位置,字符串) //在某位置插入一个串
.loadFromFile(文件名) //从文件中读入
.saveToFile(文件名) //向文件写出
【例】TMemo实现的简单的文本文件的编辑功能。
4 重要属性
.count //所包含的字符串的数目
.values[name串] //返回具有该name 的value串
◇我们在写配置文件的时候,常常用到一种叫做键-值结构的表达方法,就是name=value的形式。例如:path=c:\gyhang\t1; sendname=PA。
◇相关联的方法有:indexofName(name串) 返回该‘键’所在行号。
5 常用的不可见的字符串列表类型 TStringList
◇自定义的对象使用前一定要先创建该对象。使用后把它释放。
◇TStringList除了具有TStrings属性外,还能自动排序。
【练习】使用TStringList制作小配置文件,读出一个键的值,改变它,并存盘
四、异常和保护
传统的程序员经常是花30%的精力来完成业务流程,却要花70%的精力去防止用户的误操作或处理其它的意外情况。delphi提供了异常和保护的方法,使程序员可以从更加概括的角度用更加灵活的手段来处理错误和保护系统的资源。
1 异常的使用
try 正常操作 except 错误处理 end; // try 和 except 是关键字,与end一起构成了一个结构,这个结构中两个块,就是try块和except块。在try块中发生的任何异常都会在except块中被捕获。
在except块中,可以对不同的异常种类去执行不同的操作
◇在被捕获后,异常就消失了。如果捕获块认为自己没有完全处理好这个异常,需要外层继续处理,可以再次提起异常。方法是: except ... raise; end;
◇异常与if判断不同,它可以穿越所有的函数嵌套层次,直到被捕获为止。如果我们不定义捕获块,则delphi在最外层提供的缺剩捕获块会捕获它。这最后一关是:Application.onException,我们可以提供自己的方法来代替系统缺省动作,从而避免弹出难看的出错对话框。
◇我们可以定义自己的异常类(从Exception派生),并可以在没有发生系统异常的情况下,主动提出异常。这时,可以把自己的异常对象发送出去。在自己的异常对象中可以携带大量的数据,这就比判断简单的返回值有更多的优越性。提出异常的语法是: raise 某个异常对象;
◇我们也可以使用哑异常,来终止一次执行过程,并不显示任何错误信息。
【比较】abort exit break terminate
2 保护的使用
申请资源;try 正常操作 finally 释放资源 end;
无论在try块中发生了什么事情,finally块中的代码都会被执行的。这避免使程序中忘记了释放资源,或多次释放同一资源。
◇异常和保护经常被嵌套使用。
lst := TStringList.create;
try
try lst.loadFromFile('c:\a.txt'); ... except showMessage('文件不存在'); end;
finally lst.free; end;
◇ 也可以把finally块放在里边。这时,如发生异常,会先执行了finally块,再跳到异常处理块。一般也提倡这种方法,就是,如果发生错误,尽量早地释放资源,以免夜长梦多。
try
lst := TStringList.create;
try lst.loadFromFile('c:\a.txt'); 其它操作;
finally lst.free; end;
except showMessage('文件不存在'); end;
文章录入:cainiaowang 责任编辑:cainiaowang