1,保存所做的工作
及时地保存所做的工作至关重要。对设计者来讲,有两个文件需要保存:库单元文件(以.PAS为后缀)和工程文件(以.DPR为后缀)。
从主菜单上选择File|Save Project As...项,Delphi会显示标题为“Save Unit1 As(先保存单元)”的文件保存对话框,Delphi 2.0 允许用户更改存储路径,您可以在下拉式列表框中选择。最好将您的文件保存在自己的目录中。在编辑框中键入demoform.pas以保存库单元文件;然后显示标题为“Save Project As(保存工程)”的另一个文件保存对话框,键入
sample.dpr。Delphi保存这两个文件并返回窗体窗口。不要把库单元和工程存成一样的文件名,Delphi要求两者不同。
第一次保存后,以后可以随时通过Speed Bar中的“Save All
(ctrl+shift+s)”和“Save file”来保存工程文件和库单元文件。一般来讲,当确认文件的改变后,要同时存储这两个文件。
2,第一个范例:
Caption属性 :&RoundRec,则(按R键即触发这个键)
(1)点动写有“Additional”的页标签,切换到Additional页,找到“Shape(形状部件)”部件(其图标为圆、方形、三角形三个几何体)。Name:Shape1 (2)点动“Dialog”页标签,选择以16色网格做图标的ColorDialog部件并把它放到窗体的任意位置。因为这一部件是不可视部件,所以它的位置并不影响大局。 Name:ColorDialog1 加个按钮:ColorDialog1.Execute;
Shape1.Brush.Color := ColorDialog1.Color;
(3)“Additional”部件页,选择一个“BitBtn”按钮 (4)按钮:Shape1.Shape := stRectangle;
3. 常用的文本相关部件
它们是Label(标签)、Edit(文本编辑)、MaskEdit(格式编辑)、Memo(备注)、List Box(列表框)、Combo Box(组合框)。除了MaskEdit在Additional页之外,其它的都在Standard页中。
Label部件
Label(标签)一般放在对象的旁边,用来标记这些对象,从而对用户的操作进行提示,也可以用来显示其它信息。您可以在标签中设置热键(方法),也即在Caption属性值段中输入含有“&”的字串,当用户使用“Alt+关键字母”时,将自动选中它所指向的对象。方法是设置Label部件的FocusControl属性,在值段中,选用与它关联对象的对象名。
Edit、MaskEdit、Memo部件都是用作接收、显示用户输入文本的。它们具有一些相同的属性。ReadOnly在运行时间内控制对象是否可以进行Windows的操作,当此值为False时,该框内的文本就不能被复制到剪贴板上。
MaxLength可以设置输入文本的长度限制。用PasswordChar属性可以按照显示隐蔽密码的方法显示用户输入文本,例如,它的缺省值为“*”,运行时,您的输入将用“*”来显示,从而提供了一种安全措施。您可能也发现了,当一个字
段被加上高亮度显示时,按键操作会将这一字段删除,替换成当前的键盘输入。这种设置为操作提供了方便,您不必每次先删除原来的文本;但也可能会导致误删文本。将AutoSelect属性设置成False,这种替代功能就被取消了。
MaskEdit是格式文本输入对象。它的EditMask属性为它提供了过滤文本的格式。点动这一属性的省略按钮,会弹出过滤编辑对话框,除了Delphi为您提供的几种屏蔽格式,您也可以自己编写,查阅“帮助”,会为您提供更详细的用法介绍。
Memo是备注框,与以上对象不同的是,它可以接收多行文本输入。将ScrollBars设置成ssVertical,可以为它加上一个垂直的滚行条。Align属性调整该对象在窗口中的对齐情况,有alNone(无对齐指定)、alBottom(底部对齐)、alClient(全窗口显示)等可以选择;而Alignment属性则决定了文本在框中的对齐显示格式。Lines属性访问的文本被存储在一个TStrings对象中,按动它的省略按钮,可以通过对话框向它增加文本,也可以用程序对这一属性进行操作,以达到修改或增加备注文本的目的。
下列程序段将Edit1的文本加入到ListBox1中,并清空Edit1中的文本: procedure TForm1.AddButtonClick(Sender:TObject); begin
ListBox1.Items.Add(Edit1.text); Edit1.Text := ‘’; end;
常见的组合框初始化用以下的语句可以实现,它用下拉式列表框的第一项来初始化组合框的缺省值。
procedure TForm1.ComboBox1Text(Sender:TObject); begin if ComboBox1.Text = ‘’then
ComboBox1.Text := ComboBox1.Items.String[1] ; end;
4.一些控件简介
Speed Button部件(多个speed button按钮,制作工具条)
Speed Button(加速按钮)部件在Additional页上,是进行工具条快速设计的理想部件。它只有一个位图,没有标题。需要提起读者注意的是,用多个Speed Button制作一个工具条时,必须先放置一个窗口类部件,如Panel(操作板)、Group Box(群组框)等。否则试图将加速按钮先制作好再移上去,您会发现它会总是处于窗口类部件下面不可见。当然,您可以对加速按钮进行复制、粘贴到窗口类部件上处理,那就另当别论了。
Check Box与Radio Button部件
Radio Button是“互锁”的,用户选择定一个后,其它的将自动设置为
不选;而Check Box部件则是分立的,您可以同时选中其中的几个,也可以一个都不选。
Group Box、Radio Group及Panel部件
Group Box(群组框)、Radio Group(选项按钮组)部件都可以将部件分类、成组。它们都有标题,可以用文字表征成组部件的标题或信息。Radio Group可以进行Column和Item属性的设定,以决定其上的无线按钮的提示文本及显示格式。Panel部件也可以达到将部件分组的目的。通过编程向窗口加一个操作板部件,以书写提示和帮助信息,也不失为一种好方法。以上三个部件都在Standard页。
NoteBook、TabSet及TabbedNoteBook部件
记事本部件NoteBook一般和标签集部件TabSet共同使用,用来创制含有标签的重叠多窗体窗口。Pages属性包含了一个页名列表,在编程时,将
TabSet的Tabs属性设置成NoteBook的Pages属性,就可以使页标签和相应的窗体对应起来。
另外一个部件TabbedNoteBook是带有标签的多窗体窗口,不过,它的页标签设在窗口的上面。它们相当于多个分组部件的集合,每次查看其中的一页。以上三个部件在Win 3.1页。
在Win95页上还有TabControl、PageControl等部件。它们对于生成Windows 95风格的标签集是很重要的。
分界部件
在Win 3.1页上,还有Header(表头)部件,它在窗口中产生一个凸起的题条,提供了一个可视化的文本显示区域。Additional页的Bevel(立体框)部件提供了一个方框,它的单一线条或整个边框都可以通过Style属性设置为外凸或内凹,可以美化窗口。在Win95页上,HeaderControl、StatusBar等部件,为您使用Winows95风格的界面提供了重要元素。
Image部件
图象部件Image在Additional页上,用来在窗口中显示一幅图片,可以在picture属性中调入图象文件。Delphi支持位图(.BMP)、图标(.ICO)、图元(.WFM)三种文件格式。比较重要的属性是Autosize和Strech。它们决定了图象在窗口中的显示尺寸。Autosize属性为True表示按原尺寸显示,Strech属性为True表示图象按对象图框的大小显示,这时图象的大小可以人为改变。
PaintBox部件
在System页上还有一个PaintBox(绘图框)部件,它在窗体上为您提供一块可供绘图的区域。这一部件需要编程实现它的功能,一个只有在运行时才有效的重要属性Canvas是完成绘图的关键。PaintBox部件不能单独存在于窗体中,必须把它放在固定的分组部件中。
OutLine部件
OutLine(略图)部件在Win 3.1页上,它适用于显示分层的数据、文本。在Delphi中,略图部件具有很宽的设置范围。它的Lines属性可以设置每一词条的文本或数据。一般一个空格相当于一个层次,如果在项目前加一个空格则
表示它处于树的下一层。所以在进行Lines属性编辑的时候不能用Tab键。在编程时用Lines和Items属性来访问略图的名称、索引及完整的路径名。
OutLineStyle属性用来配置显示时关系图的风格,您可以选定用旁边有图标的缩进方式,也可以选择连线方式。
目录访问部件
Delphi为您提供了强大的文件目录访问部件。您可以针对具体的用途设计自定义的文件对话框。在部件选项板上选中System页,您将发现这些部件,它们是文件列表框FileListBox、目录列表框DirectoryListBox、驱动器下拉式列表框DriveComboBox和过滤式下拉列表框FilterComboBox部件。
文件列表框部件FileListBox显示当前目录中的文件,缺省的设置是显示所有文件。通过改变Mask属性来设置过滤器,可以适用DOS的标准通配方式,选择要显示的文件名。当指定多个过滤器时,之间用“;”隔开。
目录列表框部件DirectoryListBox显示当前驱动器内的目录,并且允许用户在程序执行时切换目录。Column属性决定目录在窗口中用多少列进行显示,当窗体空间不够时,用几列进行显示将有助于全面地显示目录信息。在Delphi中,当窗口空间显示不下全部信息时,将自动加上滚行条,以方便用户的操作。 驱动器下拉式列表框部件DriveComboBox显示当前所在的驱动器,并且在执行时允许用户在驱动器之间切换。作为程序员在应用这一部件时,应考虑当用户选择到不存在的驱动器时,进行容错、提示处理。
FilterComboBox(过滤式下拉文件列表框)部件显示当前文件过滤器类型,例如*.*,*.pas等。在执行时允许用户在下拉列表中选择要显示的文件类型。对Filter属性进行初始化,就会得到下拉式列表。
除了以上的四个部件外,在Sample页上,Delphi还提供了一个目录略图部件DirectoryOutline。它将当前磁盘中的目录结构显示成一个多层次的略图,也允许用户在运行时进行目录的层次显示切换。
滚动部件
ScrollBar部件
ScrollBar(滚行条)是在Windows应用程序中常见的结构,在Delphi中多数部件有自己的是否加入滚行条的属性ScrollBar,但一个独立的滚行条部件仍是很有意义的。它在部件选项板的Standard页,提供一种可以改变菜单或是画面中可见部分的工具,可以以一定的增量在一定范围内滚动。Position属性是个整形值,如果需要以动态的方式显示滚行条,可以在程序中通过操作这一属性来实现。 ScrollBox部件
ScrollBox(滚动框)部件是加上了水平、垂直滚行条的群组框部件,它
在Additional页上,用作在窗体中提供一个可以多方向滚行的工具。如果您只想显示较大幅面的一个部分,并允许您的用户对其进行滚行操作,ScrollBar将是理想的选择。您可以先在全幅面的滚动框中进行全面设计,然后适当地缩小外框,两个方向的滚行条将自动显示。它的Position属性是集成在
HorzScrollBar和VertScrollBar两个集属性下的,编程时,可以选定这两个属性进行操作。
几个进度显示部件
在System、Sample、Win 95、OCX等页上,Delphi还为用户提供了几个部件,完成显示进度,增量等操作。部件Gauge可以显示成长条状的或饼状的进
度指示仪表。例如在安装软件时,可以编程让这一部件显示目前安装的百分比。 微调按钮部件SpinButton含有指示向上、向下的两个按钮,它可以用来调节数值,使被控制的值按一定的增量单位,由用户操作递增或递减。
微调编辑框SpinEdit是微调按钮和编辑框的结合,它在编辑区域显示了数值,又在右侧设了微调按钮,使得用户选择调节按钮或改变数值的方式,来调整数据的值,并返回Value属性。
网格、表格部件
在Additional页中,还有字符串表格部件StringGrid,绘图表格部件
DrawGrid等。它们可以用来模拟按网格排列的事物,如成排的按键、操纵钮、字符串等。属性RowCount和ColCount设置了在网格中显示的行列的数目,设置FixedCols和FixedRows的值,可以固定一些行列避免运行时被用户改变。Options集属性含有字符串表格部件的显示方式、操作方式等,可以查阅帮助获得详细的信息,此处不再一一表述。
图形表格部件DrawGrid使得用户可以用表格的方式显示非文本的数据,它的应用面比字符串表格部件更为广泛,可以把图片和文本一起放在网格中。 颜色网格部件ColorGrid在Sample页上,它提供控制前景色和背景色的界面,通过属性ForeGroundColor和BackGroundColor可以访问到,也可以通过程序,把得到的颜色赋值给其它对象的颜色属性。
Sample页的日历部件Calendar也是用表格的方式表现的,它提供了一个简单的以月份为库单元的日历表格,通过设定Year和Month的值,可以得到相对应的月份的日历。
多媒体(MultiMedia)和OLE部件
媒体播放器部件MediaPlayer和OLE部件可以在System页上找到。媒体播放器部件在处理多媒体文件时很有用。它显示一个VCR风格的控制面板,让您记录或播放多媒体的图像、声音文件。您可以通过属性的设定来控制部件上的各个按钮,如改变显示颜色、增减按钮数目等。改变一下ColoredButtons、EnabledButtons、VisableButtons的各个子属性值,您就不难发现它们控制的显示效果。具体的应用已经超过本简介的目的,请参阅帮助以及后文的详细介绍。 OLE客户端部件OLEContainer在窗体中创建一个OLE用户区域,用于与Delphi外部的某个对象进行接口。若对外部的Paradox表格、Word文件、扩展页等进行操作,则对象本身的应用程序必须支持OLE操作。Delphi提供了支持OLE应用的对象清单,单击ObjClass属性的省略按钮,就会显示出来。具体的应用,请查阅帮助或阅读后文的详细阐述。
菜单的设计(进入菜单设计器Menu Designer,跟vc差不多) Mainmenu和popupmenu控件上双击即进入。
(1) 要加嵌入式菜单,按住ctrl+向右键; (2)设定动作:events页上OnClick事件。 (3)设定加速键和热键
您可以设定加速键,与前文的例程相同,只需在输入时,将“&”放到需要指定为加速键的字母前面,该字母将被用下划线显示,运行时,按“Alt+加速键字母”可以激活该菜单条。
设定热键也是很方便的,只需在Object Inspector中该菜单条的ShortCut属性值段的下拉菜单中,为它选定一个热键组合即可。在运行时,通过“Ctrl+热键字母”来激活菜单条。加速键和热键并不矛盾,您可以同时指定它们。
System页上的Timer控件:
Enabled属性表示了计时器打开还是关闭;用Interval属性设置两个OnTimer事件间的间隔,单位是毫秒,也即千分之一秒。将间隔置为0相当于关闭计时器,Interval的最大允许值是32767,也即32.767秒。
在窗体中放置一个计时器Timer部件,将它的Interval属性置为100(每隔10毫秒触发一次),双击部件进入代码编辑器,在它的事件中加入这样一句程序: MessageBeep(0);
使用公用对话框部件
Delphi为您在Dialogs页上提供了几个标准对话框,它们是文件打开OpenDialog;文件保存SaveDialog;字体Fontdialog;颜色ColorDialog;打印PrintDialog;打印设置PrintsetupDialog;查找FindDialog;替换ReplaceDialog等部件。
OpenDialog和SaveDialog部件
OpenDialog(文件的打开)和SaveDialog(保存对话框)部件处理文件的打开与存储,它们拥有完全相同的属性域。DefaultExt属性表示缺省扩展名。当用户没有输入文件的后缀时,可以为用户文件自动加扩展名。FileName属性指定出现在FileName正文框中的缺省文件名。Filter属性提供了文件过滤器。FileEditStyle决定在输入文件名时用Edit还是Combo- Box;设置为
fsComboBox时,允许使用历史列表HistoryList属性,这在应用程序需要经常选择文件时,可以节约大量的时间。HistoryList属性保存有在File Name下拉式编辑框中显示的文件名,使用[TStrings]的省略按钮可以编辑历史列表。您也可以编程实现将HistoryList属性设为以前用OpenDialog打开的文件名历史列表。下列程序段可以实现自动历史文件名加载: if OpenDialog1.Execute then
OpenDialog1.HistoryList.Insert(0,OpenDialog1.FileName);
ColorDialog和FontDialog
颜色对话框ColorDialog我们在前文的例程中已经用过,其更详细的功能如Options的设定请查阅在线帮助。
字体对话框Font可以帮助用户获取各种方式的字体。使用OnApply事件,可以使得Font对话框中包含一个Apply按钮,按动它,对话框中设定的字体会立即应用到指定的对象中,而对话框仍然是打开的,这样更便于观察修改的结果。 以下的例程在窗体中先放置一个按钮Button1,调用字体对话框来改变按钮上的Caption属性显示的字体:
Procedure TForm1.Button1Click(Sender:TObject); begin
FontDialog1.Execute; end;
Procedure TForm1.FontDlgApply(Sender:Tobject); begin
Button1.Font:= FontDialog1.Font;
end;
PrintDialog和PrintSetupDiaog
打印对话框PrintDialog和打印设置对话框PrintSetupDialog可以显示标准打印、打印设置对话框,支持打印文件和打印设置功能,设置它的Options属性可以规定对话框的表现形式
FindDialog和ReplaceDialog
FindDialog和ReplaceDialog提供了查找、替换两个对话框部件,对于寻找和替换文本是极其有用的。在FindDialog和ReplaceDialog中都有OnFind事件,当用户单击寻找对话框中的Find Next按钮时将触发这一事件。FindText属性中保存了用户在Find What编辑框中输入的文本。在ReplaceDialog中还有OnReplace事件,当用户单击替换对话框中的Replace和Replace All按
钮时,将触发OnReplace事件。FindText和ReplaceText属性分别保存了用户在Find What和Replace With编辑框中输入的文本。
5,创建多窗体工程项目
例一:两个窗体可以互相切换
(1)创建一个含有About框的例程
步1:Form1里一个button:打开About窗口;
步2:创建About(File->New->Form),Form2(将Form2的BorderStyle属性设置为bsDialog,则窗口成为运行时不能改变大小的对话框) 步3:代码:
uses Unit2; (unit1单元中引用unit2)
procedure TForm1.Button1Click(Sender: TObject); begin
Form2.Show; end;
步4:生成exe。(两个窗体可以互相切换) 例二:(只有modal窗关了,才可回主窗体)
在Form2窗体中添加一按钮(ModalResult属性设置为mrOK;;按钮的标签的Caption改为OK;;这样一个有模式的About框已经建成了。 将窗体Form1中Button1的OnClick处理过程的代码改变如下:
Form2.ShowModal;//(只有form2关了,才可以看到主form1)
指定自动创建窗体
有时不希望在应用程序加载时自动创建所有窗体。Delphi可以指定哪些窗体被自动创建。
选用Project|Options,Delphi显示Project options对话框。如果Forms不是当前页,按动下标签使之可见。
图示为Delphi装载的TextEdit例程(...\\Delphi 2.0\\Demos\\doc\\TextEdit.dpr)。在MainForm正文框中输入主窗体的名字。当应用程序启动时,主窗体自动打开并获取输入焦点。对MDI应用,主窗体的FormStyle属性必须设置为fsMDIForm。在Auto-created Forms列表框中列出了在启动时自动创建的窗体,缺省时工程文件的所有窗体都在此列中。
如果不需要自动创建窗体,使用箭头按钮把窗体移动到Available Forms列表框中。自动创建的窗体可以用Show方法进行显示,而不自动创建时,必须编程实现窗体的显示。在TextEdit工程中,定义一个TEditForm类型的变量EditForm,使用了以下的代码显示第二个窗体: Begin
EditForm := TeditForm.Create(Self); EditForm.Open(OpenFileDialog.Filename); EditForm.Visible := True; End;
也即,必须使用Create方法创建窗体,同时将窗体的Visible属性设为真。
6管理工程(View|Project Manager)
Project Manager 窗口上有增加、删除对象以及查看对象的加速按钮。Options加速键能够打开前文所述的Project Options对话框。如果在Project Manager打开时编辑了工程各文件的源代码,可单击Update加速条按钮刷新对象列表。
7 样板使用和保存样板
样板使用:Delphi界面座左上角,第二排(New Items)
把编好的成样板:form界面,右键->Add to Repository->选中所
需的form即可。
第二章 Delphi面向对象的编程方法
在设计用户界面时,可以使用Object Inspector(Object Inspector)来改变其属性;但有时需要在程序执行时改变属性的值,而且有些属性只能在执行时改变,这些属性在Delphi的在线帮助的“Proprety”主题中被标为执行期属性。进行这种改变,就必须使用赋值语句。 Edit1.Color := clRed;
变量定义: var
Value ,Sum : Integer; Line : String;
例子:procedure TForm1.addClick(Sender: TObject);
var
X , Y: Integer;(局部变量只能定义这。) begin
X := 100; Y := 20;
Edit1.Text := IntToStr(X + Y); end;
预定义类型
Object Pascal有多个预定义的数据类型,您可以说明任何这些类型的变量: 整形:Integer的范围是-32768到32767,占2字节的内存;Shortint从-128到127,占1字节内存;Longint从-2147443648到2147483647 占4字节内存;Byte从0到255,占1字节;Word从0到65535,占2字节内存。它们都是没有小数部分的数字。
实型:Single可以包含7到8位有效小数部分,占用4字节的内存;Double类可以包含15到16位有效小数部分,占用8字节的内存;Extended类型包含19到20位有效小数部分,占用10字节内存;Comp可以包含19到20位有效小
数部分,占用8字节内存。以上实数类型只有在8087/80287选项[N+]打开才可以使用。Real可以包含11到12位有效小数部分,占用6字节内存。它只有在和以前Borland Pascal兼容的情况下才使用,否则应使用Double或Extended。 布尔型:Boolean,只包含true或False两个值,占用1字节内存。
字符型:Char,一个ASCII字符;字符串类型String一串最长可达255个ASCII字符。
指针型:Pointer,可以指向任何特定类型。
字符串型:PChar,是一个指向以零结尾的字符串的指针。
除了预定义类型外,Delphi还有自行定义的类型。上述例程的TColor就是这种类型。此外,用户还可以定义自己的数据类型,这部分内容将在下文中详细讲述。
整型类别和实型类别都各有五种类型,同一类别中,所有的类型与其他同类别的都相容,您可以将一种类型的值赋给相同类别中不同类型的变量或属性,而只需要这个值的范围在被赋值的变量或属性的可能值范围内。例如,对于一个Shortint型的变量,可以接受在-128到127范围内的任意整数,例如Shortint类型的7;您不能将300赋给它,因为300已经超出了Shortint的范围了。将范围检查功能打开(选用Options|Project,并在Compiler Options Page中选择Range Checking),将会检查出一个范围错误;如果Range Checking没有被打开,那么程序代码将可以执行,但被赋值的值将不是您期望的值。
常量: const
Pi = 3.14159; Answer = 342;
ProductName = \"Delphi\";
Memo的使用:(将memo部件的ScrollBars属性设为ScVertical,以便加上滚行条。将WordWrap属性设置为True,这样当用户输入文本到达Memo部件的右边缘时会自动回行。将Line属性第一行的Memo1文本删除,使得memo部件在初始显示时为空的)Memo1.CutToClipboard; OpenDialog.Execute;////dlg的使用
Memo1.lines.LoadFromFile(OpenDialog.FileName);
if ColorDialog1.Execute then////if else语句 Form1.Color := ColorDialog1.Color else
Form1.Color := clRed;
Case语句:
procedure TForm1.Button1Click(Sender: TObject); var
Number : Integer; begin
Number := StrToInt(Edit1.Text); case Number of
1,3,5,7,9: Label2.Caption := '奇数'; 0,2,4,6,8: Label2.Caption := '偶数'; 10..100: /////10`100之间是复合语句 begin
Label2.Caption := '在10到100之间'; Form1.Color := clBlue; end; else
Label2.Caption := '大于100或为负数'; end; end;
Repeat语句: i := 0; repeat i := i+1; Writen(i);
until i=10;////(i=10是判断语句) while语句: i := 0;
while i<10 do begin
i := i+1; writeln(i); end; for语句 var
i : integer;
for i := 1 to 5 do writeln(i);
以上介绍了三种循环语句。如果您知道循环要执行多少次的话,可以使用for语句。for循环执行速度快,效率比较高。如果您不知道循环要执行多少次,但至少会执行一次的话,选用repeat..until语句比较合适;当您认为程序可能一次都不执行的话,最好选用while..do语句。
字符串的使用:
var {程序模块的说明部分} Name : string;
begin {程序模块的语句部分}
Name := Edit1.Text;
Edit2.Text := 'Welcome to Delphi'+Name; end; {程序模块结束}
作用域:
完整的代码结构:
Implementation(单元)之后
uses Unit1; (unit1单元中引用unit2) count:integer;(变量在这定义)
function(和procedure平行的) begin
end;
procedure之后
var定义变量处
begin
Unit1.CalculateInterest(Rate : Double);(引用函数) end;
Initialization (初始化在这)
Count:=0; end.
写了1个函数(判断edit框是否空)(Result(或者函数名)是函数的返回
值)
function NoValue(AnEditBox:TEdit):Boolean; begin
if AnEditBox.Text='' then begin
AnEditBox.Color := clRed;
AnEditBox.Text := '请输入整数值'; Result := True; end else begin
AnEditBox.Color := clWindow; Result := False; end; end;
含有参数时(函数和过程的标题):
procedure ValidateDate(Day, Month, Year : Integer);
function CalculateInterest(principal,InterestRate:Double):Double;
函数或过程被别的unit使用:
在Implementation后面的过程和函数,可以且只能被此库单元的事件处理过程使用。要让过程和函数可以被其他的程序库单元使用,则需要将过程或函数的标题部分放在库单元中的interface部分,而把含标题的整个过程或函数放在库单元的inplementation部分,并在要访问这个过程或函数的库单元的uses子句中加入说明这个过程或函数的库单元名称。
形参的两种情况(被调用函数的写法)
不改变实参的值:procedure Calculate(CalNo:Integer);
改变实参的值(相当于指针):procedure Calculate(var CalNo : Integer);
一些类型的定义(type): type
Tcount = Integer;
TPrimaryColor = (Red,Yellow,Blue); TTestIndex = 1..100; TTextValue = -99..99;
TTestList = array [TTestIndex] of TTestValue; TCharVal = Ord('A')..Ord('Z') ;
Today = (Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday) ;
函数的递归调用
implementation var
alpha:Integer;
procedure Test2(var A:Integer):forword;/////加上forward表示递归的 {Test2被说明为前置过程}
procedure Test1(var A:Integer); begin A :=A-1; if A>0 then
test2(A); {经前置说明,调用未执行的过程Test2} writeln(A);
end;
procedure Test2(var A:Integer);{经前置说明的Test2的执行部分} begin
A :=A div 2; if A>0 rhen
test1(A); {在Test2中调用已执行的过程Test1} end;
procedure TForm1.Button1Click(Sender:TObject); begin
Alpha := 15; {给Alpha赋初值}
Test1(Alpha); { 第一次调用Test1,递归开始} end;
新的数据类型
枚举类型 type
Tdays=( Sunday ,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday); var
DayOfWeek:TDays;
在枚举型中,括号中的每一个值都有一个由说明它的位置决定的整形值。例如Sunday有整形值0,Monday有整形值1等。您可以把DayOfWeek说明为一个整形变量,并将一星期的每一天赋一个整形值以达到相同的效果,但用枚举型会使得程序可读性好,编写容易。当您在枚举型中列出值时,您同时说明了这个值是一个标识符。例如您的程序中如果已经含有TDays类型且说明了
DayOfWeeks变量,则程序中便不能使用Monday变量,因为它已经被说明为标识符了。 子界类型 type
Thours = 0..23;
TValidLetter = 'A' .. 'F';
TDays = ( Sunday ,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday); {枚举型}
TWorkDay = Monday..Friday; {一个TDays型的子界}
子界型限定了变量的可能取值范围。当范围检查打开时,(在库单元的Implementation后面有{$R*.DFM}字样表示范围检查打开,否则您可以在Options|Project|Complier Options中选择Range Cheking来打开范围检查),如果变量取到子界以外的值,会出现一个范围检查错误。 数组 type
TCheck = array[1..10] of Double; 则变量说明改为: var
Check :TCheck;
( 或者直接定义:var
Check : array [1..10] of Double;)
赋值:for J := 1 to 10 do
Check[J] := 0.0; 多维数组 type
Ttable = array[1..20,1..20] of Double; var
table1:TTable; var
Col,Row:Integer; …
for Col :=1 to 20 do for Row := 1 to 20 do Table1[Col,Row] := 0.0; 字符串类型 type
MyString: string[15]; var
MyName: MyString; 赋值:
MyName := 'Frank.Smith' 集合类型 type
Tvowels=set of Char; var
Vowels:TVowels; begin
Vowels := ['a','e','i','o','u']; if Edit1.Text[1] in Vowels then Lable2.Caption := '是元音'; else
Lable2.Caption := '请再试'; end; 记录类型 type
TEmployee=record Name : string[20]; YearHired:1990..2000; Salsry: Double;
Position: string[20]; end;
var
NewEmployee,PromotedEmployee:TEmployee; 访问记录的单域:
NewEmployee.Salary := 1000;
编写如下的语句可以给整个记录赋值: with PromotedEmployee do begin
Name :='';
YearHired := 1993; Salary := 2000.00 Position := 'editor'; end;
您的程序可以将记录当成单一实体来操作: PromptEmployee := NewEmployee;
Pascal语句的架构(unit库单元:(和c++的类一样))
当您设计您的窗体时,Delphi自动建立一个和您的窗体有关的库单元。 库单元结构:(接口,实现,初始化) unit <库单元名称> interface
uses <选择性的库单元列表> {公有说明}
函数的声明在这。 implementation
uses <选择性的库单元列表> {私有说明}
{过程和函数的执行部分} initialization {选择性的} {选择性的初始化程序} end.
建立与窗体无关的新库单元
File|New Unit这时一个新的库单元加入了工程,新库单元的代码如下: unit Unit2; interface
implementation end.
With限定符(限定这个类了,这个部件了,)例: begin
ListBox1.Clear;
ListBox1.MultiSelect :=True;
end
改成: with (ListBox1) do
begin Clear;
MultiSelect :=True; end
建立非可视化对象:
type
Temployee = class(TObject); Name := String[25]; Title := String[25]; HourlyPayRate : Double;
function CalculatePayAmount:Double; end;
TEmployee只是一个对象类型,通过一个构造函数的调用从而被实例取代或创建。 var
Employee : TEmployee;
Employee := TEmployee.Create; ////才可被使用
把您的注销放在try…finally程序模块的finally部分,而把对象的程序代码放在try部分是编程的好习惯。 Employee.Free;
第三章 字符串列表(Strings属性)及应用
(1)计算列表中的字符串数目:FontCount:=Screen.Fonts.Count;(屏幕的字数目)
(2)访问指定字符串(字符串列表有一个可索引的Strings属性) 以下代码是等价的:
Memol.Lines.Strings[0]:='This is the first line.';
Memol.Lines[0]:='This is the first line.';
(3)查找字符串的位置:Indexof方法可查找指定字符串的位置。Indexof有一个字符串类型的参数,方法返回列表中匹配字符串的位置。如果列表中无匹配字符串,将返回- 1。
if FileListBox1.Items.IndexOf('AUTOEXEC.BAT') > -1 then (4)在列表中加入字符串
要把字符串加至列表尾部,使用Add方法,把字符串作为参数传递。 要把字符串插入列表中,使用Insert方法,传递两个参数:插入的位置和字符串。例如,要把“Three”插入至列表中的第三个位置,使用代码 Insert(2,'Three')
(5)在列表中移动字符串
Move方法可实现字符串的移动,它有两个参数:现行位置和要移动的位置。以下代码把第三个字符串移至第五的位置:
Move(2,4);
(6)除列表中的字符串
使用Delete方法可以删除指定的字符串。Delete的参数是指定字符串的位置,如果不知道字符串的位置,可使用Indexof方法。
要删除字符串列表中所有的字符串,可使用Clear方法。 以下代码删除列表框中的指定字符串: With ListBox1.Items do begin
if Indexof('bureaucracy')>-1 then Delete (Indexof('bureaucracy')); end;
(7)复制完整的字符串列表
Outline1.Lines:=ComboBox1.Items;///覆盖并复制
Outline1.Addstrings(ComboBox1.Items); /////加到列表的最后 (8)重复操作列表中的字符串
以下代码对列表框的字符串进行重复操作。当用户按下按钮时,对列表框中的字符串进行大小写转换。
procedure TForm1.Button1Click(Sender: TObject); var
I: Integer; begin
for I := 0 to ListBox1.Items.Count -1 do
ListBox1.Items[I] := UpperCase(ListBox1.Items[I]); end;
(9)装载,保存字符串列表
procedure TForm1.FormCreat(sender:TObject); var
FileName:String; begin
FileName:='C:\\AUTOEXEC.BAT'; With Memo1 do begin
LoadFromFile(FileName);///读取文件
SaveToFile(ChangeFileExt(FileName,'BAK'));/////保存 end; end;
(10)创建新的字符串列表 短期字符串列表
因为字符串列表要为自己和它的字符串分配内存,所以要用try..finally对列表进行保护,以确保发生异常后释放列表所占用的内存空间。 创建短期字符串列表的基本步骤为: 1. 构造字符串列表对象;
2. 在try..finally块中使用列表; 3. 在finally后释放列表空间。
以下代码创建列表、使用列表、最后释放列表空间: procedure TForm1.Button1Click(Sender:Tobject); var
TemList:TStrings; begin
Templist:=TStringList.Create;////先定义字符串(TStrings)
再赋值(TStringList.Create)
try
{ use the string list } finally
Templist.Free; end;
长期字符串列表
运行时创建字符串列表的步骤为:
1. 在程序主窗体对象的域中加入TStringsList类型的域;
2. 在主窗体的OnCreate事件中创建句柄,该事件句柄在主窗体显示前运行;
3. 在创建事件句柄后,创建字符串列表对象;
4. 在主窗体的OnDestroy事件创建句柄,该事件句柄在主窗体消失之前运行。
这样,在程序运行过程中,任何过程、事件均能访问该字符串列表。 以下代码在程序中加入了一个Clicklist的字符串列表,用户每按一次鼠标键,程序往Clicklist中加入一字符串,程序结束前把该列表存入文件。 unit Unit1; interface
uses WinTYpes, WinProcs, Classes, Graphics, Forms, Controls, Apps; type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private
{ Private declarations } public
{ Public declarations }
ClickList: TStrings; {declare the field}
end; var
Form1: TForm1; implementation
procedure TForm1.FormCreate(Sender: TObject); begin
ClickList := TStringList.Create; {construct the list} end;
procedure TForm1.FormDestroy(Sender: TObject); begin
ClickList.SaveToFile(ChangeFileExt(Application.ExeName, '.LOG')); {save the list}
ClickList.Free; {destroy the list object} end;
字符串列表除了能在Strings属性中贮存字符串外,还可以在Objects属性中贮存对象。与Stings一样,Objects也是可以索引的,它是对象的索引。
通常,创建自画式控制有以下三个步骤: 1. 设置自画风格;
2. 把图像对象加入字符串列表中; 3. 绘制自画项目。 1,步,列表框,组合框
2步:procedure TForm1.FormCreate(Sender: TObject);
var
Bitmap: TBitMap; begin
Listbox1.Items := Screen.Fonts; Bitmap := TBitmap.Create;
Bitmap.LoadFromFile('PHONE.BMP');
Tabset1.Tabs.AddObject('phone',Bitmap); Bitmap := TBitmap.Create;
Bitmap.LoadFromFile('PRINTER.BMP');
Tabset1.Tabs.AddObject('printer ',Bitmap); end;
3步:该事件叫OnMeasureItem。对于Tabset,该事件叫OnMeasureTab
第十三章 Delphi开发数据库应用程序概述
1.目前的数据库系统正向客户/服务器模式发展。客户/服务器数据库将DBMS和数据库应用程序分开,从而提高了数据库系统的处理能力。数据库应用程序运行在一个或多个用户工作站(客户机)上,并且通过网络与运行在其它计算机上(服务器)的一个或多个DBMS进行通信。
2. 面向用户的数据库应用程序开发工具,这些工具可以简化使用DBMS的过程,并且不需要专门编程。Delphi就是一种强有力的数据库应用程序开发工具。
Delphi可以访问多种数据库管理系统的数据库,凭借窗体(Forms)和报表(Reports),BDE(Borland Database Engine)可以访问诸如Paradox、dBASE、本地InterBase 服务器的数据库,也可以访问远程数据库服务器上的数据库(如ORACLE、SyBase、Informix等客户/服务器数据库中的数据库),或任何经ODBC(Open Database Connecticity) 可访问的数据库管理系统中的数据库。 3. Delphi的数据库特性
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
工具和部件 主 要 用 途
──────────────────────────────────────
Data Access Components 访问数据库、数据库表、存贮过程等
──────────────────────────────────────
Data Control Components 与用户交互,提供显示、修改数据库中数据的界面
──────────────────────────────────────
Database Desktop(DBD) 建立、索引、查询数据库表以及访问、编辑来自各数据 中的数据
──────────────────────────────────────
ReportSmith 建立、浏览和打印数据库表中的数据
──────────────────────────────────────
Borland Database Engine 数据库应用通过BDE访问dBASE Paradox数据库中的数据
(BDE) 和本地InterBase数据库服务器中的数据
──────────────────────────────────────
BDE Configuration Utility 建立和管理BDE与数据库建立连接时所使用的数据库的别名
──────────────────────────────────────
Local InterBase Server :它是一个单用户、多例程的本地SQL数据库服务器,可在单机环境下用来开发或测试客户/服务器数据库应用 程序,然后再将之扩展成一个访问远程数据库服务器ORACLE、SyBase、Informix等
──────────────────────────────────
InterBase SQL Link 连接Delphi数据库应用程序一本地InterBase服务器的
驱动程序
BDE被自动地包含在Delphi中,因此,我们在创建数据库应用程序时,不必关心BDE的有关内容。Delphi的安装程序自动为Paradox、dBASE和本地InterBaseServer 安装相应的驱动程序,并建立了有关的配置,DBE
Configuration Utility 可以建立应用程序与数据库的连接信息,还可以为数据库设置别名。
Delphi Client/server数据库特性
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 工 具 主 要 用 途
───────────────────────────────── SQL Drivers中的SQL link和ReportSmith为 SQL Drivers Delphi数据库应用程序提供了访问远程SQL 服务器的驱动程序,如访问ORACLE、SyBase、 Microsoft SQL server、Informix、Intermix
───────────────────────────────── Visual Query Builder 以可视化的方式建立SQL语句对数据库表和表 中的记录进行操作
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4.在Delphi部件板上有两页数据库部件(Data Access Components 和 Data Control Components)用于开发数据库应用程序 。 5. 数据访问部件
TDataSource:作为数据集部件TTable、TQuery、StoredProc组件与数据浏览件
TDBGrid、TDBEdit之间传送数据的通道。
TTable :它是存取磁盘上数据库表的媒介,它通过BDE存取数据库表中的数据,
TTable再与TDataSource 进行“对话”,使得数据浏览部件能够有效地TTable中访问数据并能显示和编辑其中的数据。
TQuery :它利用SQL语言访问磁盘上数据库表中的数据
TStoredProc 在应用程序中,它主要用来访问远程服务器中的存贮过程 TDatabase :当应用程序要登录到一个远程服务器上的数据库时,可以用该部
件来建立应用程序与数据库永久性的连接。
TBatchMove 用于复制数据库表的结构或表中的记录。 TReport 用于创建数据库的输出报表。
6. Fields对象是伴随着TTable、 TQuery 和TStoredproc部件的活动状态动态地建立的。
7.BDE->TTable属性设置:
DatabaseName属性指定要访问的数据库所在的路径名,路径名可以用别名来表
示。
TableName属性指定要访问数据库中具体的数据库表。
Active属性设置为True时,表示打开要访问的数据库表;设置为False时,
暂时 不打开要访问的数据库表。
缺省情况下,TTtable部件中包含了要访问的数据库表中所有的字段和记录, 用鼠标双击TTable图标时,会出现一个字段编辑器(Fields Editor),使用Fields Editor可以对TTable部件中包含的数据库表中的字段的显示格式等属性进行编辑,具体可以控制:
● 建立一个永久性的字段列表,包括字段的顺序,字段的类型等,即使磁盘上实际的数据库表的表结构发生了改变,我们建立的这个永久性的字段列表也不会发生改变
● 为每个字段指定一个便于阅读和使用的名字 ● 指定字段显示的顺序
● 为每个字段指定一个用于显示的字符串 ● 为字段增加合法性检验
● 为了显示的需要还可以建立新的字段(如可计算的字段)具体的使用方法见后面的内容
BDE->TQuery属性设置:
DatabaseName属性指定将要访问的数据库的路径名。
SQL属性指定对数据库表进行访问SQL语句,它可以是一条查询语句也可以是一条 修改语句或插入语句等。在对象浏览器上,单击SQL属性时,会打开一个字符串编辑器供程序设计者输入SQL语句。
在这里要注意在TQuery部件中,不是用TableName 属性来指定要访问的数据库中的数据库表,而是在SQL属性中,通过SQL语句来指定将要访问的数据库表。
Data Access->DataSource属性设置:Dataset属性指定一个数据集部件,可以是TTable、TQuery或TStoredProc部件的名字 Datacontrol组件:
TDBLookUpList 它是浏览数据库表中的数据的列表框,在基于一个数据库表
的应用中,用它可以显示另一个数据库表中一个指定的字段值。
TDBLookUpCombo 它是浏览数据库表中的数据的组合框,在基于一个数据库表
的应用中,用它可以显示另一个数据库表中一个指定的字段值。
8.数据库窗体专家和数据库操作台(DBD)
(Database Form Expert:在Delphi系统菜单Tool菜单下可以找到。
数据库操作台(DBD):是数据库维护和数据定义工具,程序设计人员利用它可以查询、连接、建立、重构、索引、修改和拷贝数据库表,包括Pà€aradox和dBASE文件和基于 SQL语言的数据库表。而且在使用DBD操作Paradox或dBASE的表时,用户不必拥有 Paradox 或dBASE数据库管理系统。DBD还可以把一种格式的数据和数据字典拷贝成另一种格式,例如,你可以将一个dBASE的表
拷贝到远程的SQL服务器上的一个数据库中去。有关DBD详细描述,请参看“数据库操作台(DBD)的使用”。
9. 在我们用Derphi开发一个数据库应用程序时,可能有下列四种情况。 (1)、数据库不存在或者必须要重新定义。使用DBD为本地数据库定义Paradox或dBASE 数据库表。使用Delphi提供的服务器开发工具如Windows ISQL或DBD定义本地或远程SQL数据库务器上的数据库。
(2)、数据库在桌面数据库系统中或局域网上(如Paradox或dBASE),而且BDE、数据 库和应用程序在同一台机器上,这是典型的独立应用。
(3)、数据库在桌面数据库系统中,但是用户要把它改变到SQL数据库服务器中去,这 种情况我们在附录C中详细讨论。
(4)、数据库在SQL数据库服务器中,而且应用程序将到SQL数据库服务器中去访问数据 库,这是一个标准的客户/服务器应用。 10. 数据库应用程序的开发步骤: (1)系统设计
(2)系统实现:如果应用程序是基于远程SQL数据库服务器的,在系统实现阶段
可以采用两种方法:
a.在本地InterBase服务器上,使用数据库的备份数据库进行开发和调试 b.在远程服务器上,使用数据库的备份数据库进行开发和调试
第一种方法优越性在于,它是独立于服务器的,而不至于影响服务器的其它的操作,而且不消耗服务器的资源不增加网络的负担。它的不利的方面是开发出来的应用程序只能在标准的SQL服务器上使用和调试。 第二种方法能够使程序设计人员直接感受到服务器的特性,但它在调试阶段要消耗网络和服务器
的资源,这种方法具有一定的危险性,程序中的错误可能会导致服务器的瘫痪。 (3)系统运行和维护
11. 交付数据库应用程序:
数据库应用程序生成的EXE文件和DLL文件(如果有的话) 必要的辅助文件(如Readme文件或HLP联机帮助文件) 支持访问数据库的BDE,有时也称为IDAPI 用于打印输出报表的ReportSmith报表工具
如果应用中使用了VBX控件,还要包括VBX和BIVBXII.DLL 12.安装BDE
在交付数据库应用程序时,必须同时在运行应用程序的机器上安装BDE,Delphi 本身包含可再安装的BDE,在准备数据库应用程序安装盘时,同时从Delphi中复制一份BDE 到最终用户的机器中,BDE中包含访问多种数据库系统的驱动程序,为了节省磁盘空间, 在安装BDE时,可以只安装应用程序必须的驱动程序,例如, 如果我们的应用程序只需要访问dBASE数据库文件,那么在安装BDE时,只需安装dBASE的驱动程序就行了。要访问Paradox数据库,BDE至少需要500KB的磁盘空间。BDE主要包括下列文件,请参看DEPLOY.TXT文件。
运行Delphi的安装程序setup.EXE, 因为我们只须安装BDE,所以只要选择Borland Database Engine检查框,如果应用程序要处理SQL数据库服务器上的数据,还必须要选择SQL Links 检查框, 以便安装 SQL Links。单击Continue按纽,完成BDE的安装。
13.安装SQL Link
安装SQL链接与安装BDE执行相同的步骤,在图13.7中只选择SQL Link检查框,然后执行安装,选择应用程序要访问的SQL数据库服务器,当选择安装
SQL Link时, 安装程序会自动地安装BDE。根据用户选择的SQL数据库服务器,安装程序会自动地提示相关的特定信息,例如Informix数据库系统的链路(SQL Link)需要一个放置消息文件的地方。用户选择的每个SQL Link都使用一个或多个附加的动态链接库(DLL文件),这些文件将要拷贝到BDE目录中,下面是建立SQL Link时常见的SQL数据库系统所需的DLL文件。 1.ORACLE数据库
在建立ORACLE的SQL Link时除了需要下列文件外,应用程序还需要ORACLE数据库管理系统的客户端的连接产品与网络协议接口。 表13.6 建立ORACLE数据库的SQL Link所需的文件
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 文件名 描 述
─────────────────────────── SQLD_ORA.DLL Borland SQL Link for ORACLE驱动程序 SQLD_ORA.HLP 联机帮助文件
SQL_ORA.CNF ORACLE驱动的BDE配置文件 ORA6Win.DLL ORACLE 6.x版客户端的DLL文件 ORA7Win.DLL ORACLE 7.x版客户端的DLL文件 SQL13Win.DLL ORACLE 客户端的DLL文件 SQLWin.DLL ORACLE 客户端的DLL文件 COREWin.DLL ORACLE 客户端的DLL文件 ORAWE850.Ld ORACLE 的语言驱动程序
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. Sybase和MicroSoft SQL Server数据库
在建立Sybase或MicroSorft SQL Server的SQL Link时除了需要下列文件外, 应用程序还需要Sybase数据库管理系统的客户端的连接产品与网络协议接口。 表13.7 建立Sybase数据库的SQL Link所需的文件
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 文件名 描 述
─────────────────────────── SQLD_SS.DLL BDE SQL Link for Sybase的驱动程序 SQLD_SS.HLP 联机帮助文件
SQL_SS.CNF Sybase驱动程序的BDE配置文件
W3DBLIB.DLL Sybase/MC SQL Server客户端的DLL文件 DBNMP3.DLL Sybase/MC SQL Server客户端的DLL文件 SYDC437.LD Sybase语言驱动程序 SYDC850.LD Sybase语言驱动程序
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3. Informix数据库
在建立Informix的SQL Link时除了需要下列文件外,应用程序还需要Informix数据库管理系统的客户端的连接产品与网络协议接口。
表13.8 建立Informix 数据库的SQL Link所需的文件
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 文件名 描 述
─────────────────────────── SQLD_ss.DLL BDE SQL Link for Informix的驱动程序 SQLD_INF.HLP 联机帮助文件
SQL_INF.CNF Informix驱动程序的BDE配置文件 LDLLSQLW.DLL Informix客户端的DLL文件 ISAM.IEM Informix错误信息文件 OS.IEM Informix错误信息文件 RDS.IEM Informix错误信息文件
SECURITY.IEM Informix错误信息文件 SQL.IEM Informix错误信息文件
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.InterBase 数据库
在建立InterBase的SQL Link时除了需要下列文件外,应用程序还需要InterBase数据库管理系统的客户端的连接产品与网络协议接口。 表13.9 建立InterBase数据库的SQL Link所需的文件
━━━━━━━━━━━━━━━━━━━━━━━━━━━ 文件名 描 述
─────────────────────────── SQLD_IB.DLL BDE SQL Link for InterBase的驱动程序 SQLD_IB.HLP 联机帮助文件
SQL_IB.CNF InterBase驱动程序的BDE配置文件 CONNECT.EXE InterBase连接测试诊断工具
CONNECT.HLP InterBase连接测试诊断工具的帮助文件 GDS.DLL InterBase API DLL
REMOTE.DLL InterBase与网络的接口的DLL文件 INTERBASE.MSG InterBase错误信息文件
第十四章 简单数据库应用的创建及MASTAPP介绍
1.本章所介绍的例子中用到的窗体、数据库表以及相关的文件都是在安装Delphi时缺省安装在C:\\DELPHI\\DEMOS\\DB\\MASTAPP目录中,并且用别名DBDEMOS表示这一子目录
2. 简单的基于单表的据库应用
Ttable,TDatasounce, TDBGrid(可视)三个部件。 属性设置: DataSource1.AutoEdit False
DataSource1.DataSet Table1 Table1.DatabaseName DBDEMOS Table1.TableName CUSTOMER.DB
Table1.Active True
DBGrid1.DataSource DataSource1
(Table1.Active设置为True时,Delphi会打开Table1.TableName所指定的数据库表。如果这个数据库表不存在(或表中什么也没有, 即空表), Delphi 会弹出出错信息并且Table1.Active变成False。当Table1.Active被设置成True之后,Table1 部件的一些属性就不能再修改了,如Table1.DatabaseName和Table1.Tablename属性。若要修改它们, 必须首先要将Table1.Active属性设置为False,然后再进行修改,否则,Delphi会弹出错误信息“Cannot perform this operation on an open database”。当看到这个错误信息时,只需把Table1.Active置成False,完成相关的修改后,再把 Table1. Active 属性设置为True。)
3.利用TDBNavigator部件创建存取程序
Ttable,TDatasounce;TNavigator和若干TEdit(需要显示的字段的个数) 属性设置:Ttable,TDatasounce(同上)
Navigator和所有的Edit的 DataSource DataSource1 注:TEdit的 DataField选择显示的字段。
TNavigator的ShowHint(显示提示信息);VisibleButtons(需
要显示的按钮);ConfirmDelete(与delete按钮合).
4.创建主要──明细数据库应用
用到的控件:TTable1,TDatasource1;;TTable2,TDatasource2;;
TGrid1,Tgrid2;TNavigator(1是主要表,2是明细表)
属性设置:TTable1的Active True;;DatabaseName DBDEMOS;;
TableName CUSTOMER.DB;;
DataSource1 DataSet Table1;;AutoEdit False
TTable2的Active True;;DatabaseName DBDEMOS;;
TableName CUSTOMER.DB;;
IndexFieldNames CUSTNO (指定字段CUSTNO作为 Table2中的索引字段)
MasterField CUSTNO (指定与主表发生联系 的字段)
MasterSource DataSource1 (说明与主表相连接的 数据源即DataSource)
DataSource2 DataSet Table2 ;;AutoEdit False DBGrid1 DataSource DataSource1 DBGrid2 DataSource DataSource2
DBNavigator1 DataSource DataSource1
控件里唯独TTable2得好好设置:(IndexFieleName明细表的索引;;
MasterField和MasterSource是与主要表联系的)
字段对象不可见,只能通过Fields Editor来设置。
5创建永久的字段对象(只显示需要的字段)
(1)选中Table1并双击鼠标左键,打开字段编辑器Fields Editor, 缺省情况下字段列表为空 。右键->Add Fields(Ctrl选中需显示的字段)。在Editor中可以直接拖改变显示的顺序。 (2)字段的重要属性:
Alignment 说明字段值的显示方式:左对齐、右对齐、居中
Calculated 当该属性值为True时,表明该字段的值是根据其它字段的值计算
得来的。否则该字段是数据库表中的字段
DisplayLabel 说明字段在网格部件中显示时的标题
DisplayWidth 说明字段在网格中显示时所点的列宽度,即字符数
DisplayFormat 说明字段在显示和编辑状态下的显示格式和输入的过and
EditMask 滤条件(限定用户输入字段值的范围)。
FieldName 在数据库表中对应于该字段对象的字段名称
Index 指定该字段对象在数据集部件中的逻辑位置,如Table1中的第一个字段对象的Index值为
Name 字段对象的名称,通过字段对象的Name属性可以访问该字段的值,如
Table1CUSTNO.Value(ttable+字段名) ReadOnly 说明该字段是否能被修改,
Visible 当该属性值为True时,在与之相连的网格部件中将不显示该字段 (3)动态字段对象的访问:两种方法
法一:Table1.Fields[0].DisplayLabel:='标识符'//修改第一个字段的
标识符
法二:在TTable部件中,提供了一个名为FieldByName的方法以便让我
们通过列名访问字段对象。
Table1.FieldByName('CustNo').DisplayLabel:='标识符'
例:在窗体的Oncreate事件处理过程中访问字段对象。
procedure TForm1.FormCreate(Sender:TObject); Begin
with Table1 Do begin
{通过索引号访问字段对象}
Field[0].DisplayLabel:='客户编号'; {通过字段名访问字段对象}
FieldByName('Company').DisplayLabel:='公司名称'; FieldByName('Phone').DisplayLabel:='电话号码';
FieldByName('LastInvoiceDate').DisplayLabel:='购买日期'; end;
end;
(4) 永久性字段对象的访问
Table1CustNo.DisplayLabel:='客户编号'; (5) 字段对象的读取和赋值
字段对象的字段值可以转换成以下几种类型的数据: AsString: 将字段值转换成字符串数据
AsBoolean: 将字段值转换成布尔型数据 AsDateTime: 将字段值转换成日期时间数据 AsFloat: 将字段值转换成数值型数据 AsInteger: 将字段值转换成整数型数据 例:Edit1.Text:=Table1Company;{类型相匹配,不需要转换}
Edit1.Text:=Table1CustNo.AsString;{类型不匹配,需要转换}
(6)设定字段对象的显示格式
a,TaxRate字段: DisplayFormat属性设为0.00% ,若TaxRate的值为
0.085那么在网格部件中其显示的格式为8.50%。
b,在运行过程中我们通过程序代码来设定字段Phone的显示格式, 美国的电话表示形式与中国的表示形式不一样(如美国808-555-0269,中国(808) 5550269 ), 为此我们将phone 字段的值表示成中国式的形式。 具体方法是:在 Object Inspector 中选取Table1phone对象,并为此对象的OnGetText事件编写如下程序代码: TForm1.Table1PhoneGetText(Sender:TField; Text:OpenString;DisplayText:Boolean); begin
If DisplayText then
begin
Text:=Table1Phone.Value;/////(访问字段只能通过字段name) Delete(Text,4,1);(删除第几个字符) Delete(Text,7,1);
Insert('(',Text,1);(第几个间隔处插入) Insert(')',Text,5); end; end;
(7)自定义字段以及计算字段对象的创建
Fields Editor窗口中,单击鼠标右键,选择New Fields
(Field Type列表框中的Currency 项, 并在Field Name文体框中输入Balance,修改其 Calculated属性值为True)
Table双击OnCalcField事件,为Table1OnCalcField编写事件处理过程如下:(只能为Table添加OnCalField事件)
procedure TForm1.Table1OnCalcFields(DataSet:TDataSet); begin
Table1Balance.Value:=Table1ItemsTotal.Value-Table1AmountPaid.Value; end;
6查询数据库中的记录
(1)精确查找(使用FindKey方法方便)
法一:使用GotoKey方法查找数据记录
procedure TForm1.Button1OnClick(Sender:TObject); begin
with Table1 do
begin
Label1.Caption:=' '; Label1.Caption:=' ';
IndexFieldName:='CustNo';/////索引字段(首先必须确定) setkey;///////////////设置成查找方式
FieldByName('CustNo').AsString:=Edit1.Text;///索引字段的值
If GotoKey then////GotoKey开始查找,成功的话,指针指向一条记录 begin
Label1.Caption:='查找成功';
Label1.Caption:=FieldByName('Phone').AsString;/记录的某个字段值 end; else
Label1.Caption:='查找失败'; end;
法二:使用Findkey方法
procedure TForm1.Button1OnClick(Sender:TObject); var
SeekValue:string; begin
with Table1 do begin
Label1.Caption:=' '; Label1.Caption:=' ';
IndexFieldName:='CustNo'; /////索引字段(首先必须确定) SeekValue:=Edit1.Text;
If FindKey([SeekValue]) then//////直接查找需要值得记录,指针
并指向一条记录
begin
Label1.Caption:='查找成功';
Label1.Caption:=FieldByName('Phone').AsString;/记录的某个字段 end; else
Label1.Caption:='查找失败'; end;
(2)不精确查找
GotoNearest和FindNearest(同上边的key) 例:GotoNearest:
procedure TForm1.Button1Click(Sender: TObject); begin
with table1 do begin
IndexFieldNames:='Company'; setkey;
FieldByName('Company').AsString:=Edit1.text;////随便输 GotoNearest;/////不用判读返回值(指针肯定会指向一条记录) label3.caption:=FieldByName('Company').AsString; end; end;
7 修改数据库中的记录
(第一步:first定位记录(行);
第二步:FieldByName(TargetField).AsString;()列)
unit Unit26; interface uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, DBGrids, ExtCtrls, DB, DBTables, Buttons; type
TForm1 = class(TForm) DataSource1: TDataSource; customerTable: TTable; Panel1: TPanel; DBGrid1: TDBGrid; Panel2: TPanel;
UpperCaseFirstAddBtn: TButton; UpperCaseSecondAddBtn: TButton; MixedCaseFirstAddBtn: TButton; MixedCaseSecondAddBtn: TButton; BitBtn1: TBitBtn;
////////声明(也不知道自动生成的 还是 自己定义的)
procedure ForceCase(TargetField:String;ToUpper:Boolean); procedure UpperCaseFirstAddBtnClick(Sender: TObject); procedure MixedCaseFirstAddBtnClick(Sender: TObject); procedure UpperCaseSecondAddBtnClick(Sender: TObject); procedure MixedCaseSecondAddBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private
{ Private declarations } public
{ Public declarations } end; var
Form1: TForm1; implementation const////常量定义 upper=true;
Mixed=False; {$R *.DFM}
Function IsUpper(ch:char):Boolean; begin
If (ch>='A')and(ch<='Z')then IsUpper:=true else
IsUpper:=False; end;
procedure TForm1.ForceCase(TargetField:String;ToUpper:Boolean); var
WorkBuffer:string; i:Integer; begin
with customerTable do begin
DisableControls;////先disable控件,切断datasource和table通道 TRY
First; {将记录指针移到第一条记录处 } While not EOF do begin
WorkBuffer:=FieldByName(TargetField).AsString;///workbuffer字符
数组
If ToUpper then
for i:=1 to Length(WorkBuffer)do
WorkBuffer[i]:=UpCase(WorkBuffer[i]) else begin
for i:=1 to Length(WorkBuffer) do If IsUpper(WorkBuffer[i]) then
WorkBuffer[i]:=chr(ord(WorkBuffer[i])+32); WorkBuffer[1]:=UpCase(WorkBuffer[1]) end;
Edit;/////激活成编辑状态,下边修改记录
FieldByName(TargetField).AsString:=WorkBuffer; post;/////将修改的结果提交 Next; end; Finally
enableControls; end; end;
end;
procedure TForm1.UpperCaseFirstAddBtnClick(Sender: TObject); begin
ForceCase('Addr1',Upper); end;
procedure TForm1.MixedCaseFirstAddBtnClick(Sender: TObject); begin
ForceCase('Addr1',Mixed); end;
procedure TForm1.UpperCaseSecondAddBtnClick(Sender: TObject); begin
ForceCase('Addr2',Upper); end;
procedure TForm1.MixedCaseSecondAddBtnClick(Sender: TObject); begin
ForceCase('Addr2',Mixed); end;
procedure TForm1.FormCreate(Sender: TObject); begin
customerTable.open;////// FormCreate里打开表 end; end.
8 插入和删除记录
(第一步:IndexFieldName定位字段(列); 第二步:FindKey定位具体值(行))
unit tt; interface uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
StdCtrls, Forms, DBCtrls, DB, DBGrids, Buttons, DBTables, Grids, ExtCtrls,Mask,Dialogs; type
TForm1 = class(TForm) DBGrid1: TDBGrid;
DBNavigator: TDBNavigator; Panel1: TPanel;
DataSource1: TDataSource; Panel2: TPanel;
customerTable: TTable;
BitBtn1: TBitBtn; Label1: TLabel; Label2: TLabel; BitBtn2: TBitBtn; BitBtn3: TBitBtn; CustNoEdit: TEdit; CompEdit: TEdit;
procedure FormCreate(Sender: TObject); procedure BitBtn2Click(Sender: TObject); procedure BitBtn3Click(Sender: TObject); procedure FormActivate(Sender: TObject); private
{ private declarations } public
{ public declarations } end; var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject); begin
customerTable.Open; end;
procedure TForm1.BitBtn2Click(Sender: TObject); begin
If (Length(CustNoEdit.text)=0)and (Length(CompEdit.text)=0) then
MessageDlg('没有输入新记录的字段值!',mtError,[mbCancel],0)///用法 else
with customerTable do begin
IndexFieldNames:='CustNo';
If FindKey([CustNoEdit.text]) then
MessageDlg('已经存在这条记录!',mtError,[mbCancel],0) else
InsertRecord([StrToInt(CustNoEdit.text),CompEdit.text,nil]);//插入 CustNoEdit.text:=' ';
CompEdit.text:=' '; end; end;
procedure TForm1.BitBtn3Click(Sender: TObject); begin
If (Length(CustNoEdit.text)=0)and (Length(CompEdit.text)=0) then
MessageDlg('没有输入删除的记录的字段值!',mtError,[mbCancel],0) else
with customerTable do begin
IndexFieldNames:='CustNo';
If FindKey([CustNoEdit.text]) then begin
If MessageDlg('你确定要删除这条记录吗?',mtConfirmation, [mbYes,mbno],0)=mrYes then Delete; end else
MessageDlg('没有你要删除的记录!',mtError,[mbCancel],0); CustNoEdit.text:=' '; CompEdit.text:=' '; end; end;
procedure TForm1.FormActivate(Sender: TObject); begin
CustNoEdit.setfocus; end; end.
第十五章 数据访问部件的应用及编程 Delphi数据访问部件的层次结构
TSession是全局性的部件,在应用程序运行时,它自动地建立,在设计阶段和运行过程中它是一个不可见的部件。
TDatabase部件是为开发客户/服务器数据库应用程序时,设置登录的数据库的有关参数的,它在数据访问部件页上。
TDataset部件是不可见的,TTable和TQuery部件是由它派生而来的,这两个部件一般被称为数据集部件,它们在数据访问部件页上。
TDatasource部件是连接数据集部件和数据浏览部件的桥梁,它在数据访问部件页上。
TFields部件对应于数据库表中的实际字段,它既可以在应用程序的运行过程中动态地生成也可以在程序设计阶段用字段编辑器创建。它是不可见的部件,在程序中我们可以通过TField部件来访问数据库记录的各个字段值。
1.Tsession部件及其应用
通过TSession部件获取数据库的有关信息
窗体中主要使用了两个列表框(TListBox),其中列表框DatabaselistBox用于显示数据库的名字,列表框TablelistBox用于显示数据库中的表名。程序运行完后数据库的名字显示在DatabaselistBox列表框中,当用户单击
DatabaselistBox列表框中的数据库名时,该数据库全部的数据库表的名字将会显示在TablelistBox列表框中.代码如下:
procedure TQueryForm.FormCreate(Sender: TObject); begin
with ListBox1 do begin
Items.Clear;
Session.GetAliasNames(Items);///数据库名显示在ListBox1中。 end;
procedure TQueryForm.ListBox1Click(Sender: TObject);(listbox1的
Click事件)
var(定义变量)
strValue: string; { Holds the alias selected by the user }
bIsLocal: Boolean; { Indicates whether or not an alias is local }
slParams: TStringList; { Holds the parameters of the selected alias } iCounter: Integer; { An integer counter variable for loops} begin
with ListBox1 do
strValue := Items.Strings[ItemIndex];///获取到listbox1里的名字
ListBox2.Items.Clear;
Session.GetTableNames(strValue, { alias to enumerate }
'', { pattern to match } /////获取到数据库里的表名显示在listbox2中
2数据集中的数据维护
(1)Append方法和Insert 方法:这两个方法都是将数据集部件置成插入状态,Insert方法是在当前指针位置的记录后面插入一打新记录,Append方法是在表的尾部插入一打新记录最后调用post方法,将插入的记录写回数据库表。调用这两种方法插入新记录的一般步骤如下: With tabe1 DO Begin
Insert; {调用Insert方法,插入一条空记录} <为记录的各字段赋值> Post; End;
(2)Delete方法:Delete方法用于删除表中的记录,调用Delete方法时,将会删除表中当前的记录,并且自动地将记录指针移到被删记录的下一条记录,同时将数据集置成Browse状态。
(3)Cancel方法:Cancel方法用于取消当前的操作,当程序还没有调用Post方法,将对记录的修改写回数据库表时,调用Cancel方法,可以将记录恢复到没有修改之前的状态。并且在调用Cancel方法时,它总是将数据集置成Browse状态。
(4)AppendRecord方法和InsertRecord方法:这两个方法分别与Append方法和Insert方法相似。但AppendRecord方法和InsertRecord方法比Append和Insert方法更简单更方便一些,它们直接在表中插入一条新记录,新记录的各个字段值作为AppendRecord或InsertRecord方法的参数传递给新记录并且不需显式地调用post方法,将插入的新记录写回数据库表。
(5)SetRecords方法:调用该方法可以修改表中当前记录的多个字段的值, Table1.Edit;
Tabel1.SetRecord(, , ,9600000,1200000000); Tabel1.post;
(6)取消删除操作:
Tabel1.BeforeDelete(DataSet:TDataSet); If MessageDlg('真的要删除记录吗?',
mtConfirmation,mbyesNoCanel,0 <> mryes then Abort; {取消删除操作}
(7)关于书签(BookMark)(也是指针)操作(三步) BookMark : TBookMark; BookMark := Table1.GetBookMark; {对当前记录作书签标志} Table1.DisalbeControls; {切断Table1与数据察觉部件的联系} Table.First While Not EOF Do {对表中全部记录进行其他处理} begin Tabel1.GotoBookMark(BookMark) {重新定位记录指针回到原来的位置} Table1.enableControls; Tabel1.FreeBookMark(BookMark); {删除书签BookMark标志} 3.数据集部件TTabel和TQuery具有三个方法,DisableControls 方法、EnableControls方法、Refresh方法用于控制数据集部件和与其相连的数据浏览部件之间的连接,以及控制数据浏览部件的显示。 数据集部件常用的事件: BeforeOpen,Afteropen 在数据集部件被打开之前/之后被触发 BeforeClose,Afterclose 在数据集部件被关闭之前/之后被触发 BeforeInsert,AfterInsert 在数据集部件进入插入状态之前/之后被触发 BeforeEdit,AfterEdit 在数据集部件被编辑之前/之后被触发 BeforePost,AfterPost 在数据集部件投寄被修改的记录之前/之后被触发 BeforeCancel,AfterCancel 在数据集部件取消前一步操作之前/之后被触发 BeforeDelete,AfterDelete 在数据集部件删除当前记录之前/之后被触发 OnNewRecord 当建立一条新记录时被触发 OnCalcFields 当为表中的计算字段计算字段值时被触发 4 TTable部件及应用 (1)重要的属性: DatabaseName属性和TableName属性: DatabaseName属性常常是一个由BDE定义的数据库的别名。使用由BDE定义的数据库的别名代替数据库实际所在的路径和名字,好处是当实际的数据库存放的位置发生变化时,只需利用BDE简单地设置一下该数据库的别名,而数据库应用程序无需修改。有关BDE的使用请参看BDE的设置应用。TabelName属性用以说明当前TTable部件所连接的实际的数据库表。 这两个属性一般都在设计阶段指定,当然在程序运行过程中也可以设置,但是要修改这两个属性时, 必须要在TTabel的Active属性为False时进行, TableType属性: 当TableType属性设置成Default时,该属性所说明的数据库表的类型由数据库文件的扩展名决定。 若数据库文件的扩展名为.DB或没有扩展名,表的类型是Paradox表 若数据库文件的扩展名为.DBF时,表的类型是dBASE表 若数据库文件的扩展名为.TXT时,表的类型是ASCII表 KeyExclusive属性: 该属性的一个作用是说明在数据库表中查找记录时,将记录移到与查找值相匹配的记录处还是将记录指针移到与查找值相匹配的记录后面一条记录处。 该属性是布尔型变量,当它的值为False时(缺省情况下为False), 将记录指针移到相匹配的记录处,为True时,将记录指针移到相匹配记录的后面一条记录处。 该属性另一个作用是在表中指定检索范围时,用来说明是否包括满足过滤条件的边界记录。当KeyExclusive的值为False时,检索范围包括边界记录,否则不包括边界记录,有关详细的操作请参看“限定表中记录的检索范围”。 IndexFields属性和IndexFieldsCount属性: IndexFields的属性值是数据库表中字段名列表,它包含与TTable部件相连的数据库表中的全部索引字希。IndexFieldsCount属性说明表中索引字段的个数。这两个属性值都是只读的,只有在程序运行过程中可用。 IndexName属性和IndexFieldNames属性: IndexName属性中存放着在建立数据库表时为数据库表定义的所有辅助索引名,它是一个辅助索引名列表,是只读属性。IndexFieldNames属性指定用于数据库表索引排序的字段名,多个字段名之间用分号隔开。例如对Customer.DB表中的客户记录按邮政编码ZipCode和客户号码CustNo排序时可以设定IndexFieldNames的值为: ZipCode ; CustNo Exclusive属性: 该属性是一个布尔型属性,它标明是否以共享方式打开数据库表, ReadOnly属性和CanModify属性: 这两个属性都是布尔型属性,ReadOnly属性决定用户是否能够对表中的数据进行读写。ReadOnly为True 时,用户只能读取表中的数据,ReadOnly为False时,用户可以读写表中的数据(假设数据库已授权用户能够读写其中的数据库表)。CanModify属性是一个只读属性,用户不能够修改其属性值,它反映了用户对数据库表拥有的实际特权,当ReadOnly为True时CanModify将自动地被置为False,当ReadOnly为False时,如果数据库允许用户对表进行读写时,CanModify为True,否则CanModify为False。当CanModify为False时,数据库表是只读的,但不能将其置成编辑状态或插入状态;当CanModify属性为True时,虽然数据库表对应的数据集部件可以置成编辑和插入状态,但是这并不意味着用户能够插入和修改表中的数据,因为这还要受到其他因素的限制,如用户对SQL数据库服务器的访问权限等的限制。 (2)方法 设定数据库表的使用范围 SetRangeStart和EditRangeStart方法 SetRangeEnd和EditRangeEnd方法 SetRange([Start Values],[End Values])方法 ApplyRange方法 CancelRange方法 例子: Tabel1.SetRangeStart; {指定检索范围的起始记录} Tabel1CustNo.AsString:= StartVal.Text {为起始记录的CustNo字段指定字段值} Tabel1.SetRangeEnd; {指定检索范围的结束记录} if EndVal.Text <> ' ' then Tabel1CustNo.AsString := EndVal.Text; {为结束记录的CustNo 字段指定字段值} Tabel1.ApplyRange; {根据检索范围的起始、结束记录设定检索范围} 等价于:If EndVal.Text <>' ' then Tabel1.SetRane([StartVal.Text].[EndVal.Text]); Table1.ApplyRange; 查找数据库表中的记录 例如:SetKey用法和FindKey用法(FindKey用法方便) Table1.Open;////首先打开表 Table1.SetKey; Table1.Field[0].AsString:= 'Smith'; If not Table1.GotoKey then ShowMessage('记录没找到') 等价于:Table.FindKey([Edit1.Text]);(一句话) 创建主要──明细数据库应用 多个字段:如Table1.MasterFields := 'OrderNo;CustNo'。 也可以使用Field Link Designer进行关联。 5 TDataSource部件及应用 TDataSource部件具有三个事件: OnDataChange事件:当与TDataSource相连的数据集中的记录指针的位置发生 改变时。该事件一般用于保持应用中多个部件之间的同步。 OnStateChange:State属性标明了数据集部件当前所处的状态。 OnUpdataData:当数据集部件中当前记录将要被修改时,触发该事件。 OnStateChange使用例子: TForm1.DataSource1OnStateChange(Sender : Tobject); var S : String; begin Case Table1,State of dsInactive : S := 'Inactive'; dsBrowse : S := 'Browse'; dsEdit : S := 'Edit'; dsInsert : S := 'SetKey'; dsSetKey : S := 'SetKey'; end; Label1.Caption := S; end; 例子2:Form1.DataSource1OnStateChange(Sender : Tobject); begin InsertBtn.Enabled := (Table1.State = dsBrowse); CancelBtn.Enabled := Table1.State in [dsInsert,dsEdit,dsSetKey] end; 6 字段 字段部件的类型 对应的数据类型: TStringField 字符串类型的字段 TSmallIntField 短整数类型的字段 -32768-32767 TIntegerField 整数类型的字段 TWordField 正整数类型的字段0-65535 TBooleanField 布尔型字段 TFloatField 浮点数类型的字段 TCurrenCyField 货币型字段 TDataField 日期型 TTimeField 时间型 TBCDField 小数位数固定的浮点数 TDataTimeField 日期时间型字段 数据库表的每一列在应用程序中都有其对应的一个字段部件,在缺省情况下当TTable或TQuery的Active属性被置为False或调用close方法时,与表中各列对应的字段部件也随即消失,要想为应用程序创建永久性的字段部件,我们必须要在程序设计阶段使用字段编辑器(Fields Editor)来创建 字段输入模式编辑器 (EditMask属性) Delphi本身为某些类型的字段对象提供了设定其显示和编辑格式的例程,并且为字段部件的DisplayFormat和EditFormat属性指定了缺省值, 字段部件的事件 OnChange 当字段部件的字段值发生改变时,触发该事件 OnGetText 当字段部件获得字段值时,触发该事件 OnSetText 当字段部件被设置字段值时,触发该事件 OnValidata对字段值进行有效性检验时,触发该事件 (用户想自己设定字段的显示和编辑格式时,可以编写OnGetText事件和OnSetText事件的处理过程,以达到设定字段的显示和编辑格式。) 7,TReport部件及其应用 ReportName属性:说明报表文件的名字,就是用ReportSmith创建的报表文件。 ReportDir属性:说明报表文件所在的途径名。 PreView属性:若它的值为True,那么在执行报表功能时,只是在屏幕上显示报表;若它的值为False,则报表内容将在缺省的打印机打印出来。 AutoUnload属性:布尔型属性,它的值为True时,在执行完一个报表功能后,自动地从内存中卸出ReportSmith工具;它的值为False时,在运行完一个报表功能后,不从内存中卸出ReportSmith工具。一般情况下,如果应用程序只有一个报表或者只有较少的报表要输出时,应设置AutoUnload属性为True,如果应用程序一次要输出多个报表,那么要应设置AutoUnload属性为False。 InitialValues属性:这是一个字符串类型的属性,它是说明报表文件中使用的变量,每一条说明一个变量。如: ReportVAR := Value; 第十六章 数据浏览部件的应用及编程 1,Enabled属性:当数据浏览部件连接到数据集部件时,它的Enabled属性决定了数据浏览部件能否接受来自鼠标、键盘和定时器事件的消息。 2,其数据库应用程序创建的一般步骤如下 (1).在窗体中放置上述所说的部件并连接数据集部件、数据源部件。 (2).为各数据浏览部件设置DataSource属性值为窗休中存在的TDataSource部件的名字。 (3).设置各数据浏览部件的DataField属性为数据集部件TTable或TQuer 部件中存在的 字段部件的名字。(TDBGrid部件和TDBNavigator部件没有DataField属性的), 3,使用TDBEdit部件显示和编辑(修改)表中的数据 用户希望能通过TDBEdit部件编辑修改数据库表中的字段值,还要设置TDBEdit部件的ReadOnly属性为False,设置与TDBEdit相连的数据源部件TdataSource部件的AutoEdit属性为True以及确保与TDataSource部件相连的数据集部件TTable或TQuery部件处于编辑状态,即设置它们的CanModify属性为True。 Table1.DatabaseName DEMOS Table1.TableName Customer.DB Table1.CanModify True DataSource1.DataSet Table1 DataSource1.AutoEdit True DBGrid1.Datasource DataSource1 DBGrid1.ReadOnly False 4,DBGrid部件 TDBGrid部件中的主要事件 DBGrid事件名目的用途(非常有用) OnColEntor 当用户进入网格各列时,触发该事件 OnColExit 当用户离开网格各列时,触发该事件 OnDblClick 当用户在网格中双击鼠标左键时,触发该事件 OnDragDrop 当用户在网格中用鼠标进行拖放操作时,触发该事件 OnDragOver 当用户在网格中用鼠标拖动网格时,触发该事件 OnDrawDataCell 用于定制绘制网格中各网格单元,当向网格中填充数 据时触发该事件 OnEndDrag 当用户停止拖动网格时,触发该事件 OnEnter 当网格获得焦点时,触发该事件 OnExit 当网格失去焦点时,触发该事件 OnKeyDown 当用户在网格中按下任何键或组合键时,触发该事件 OnKeyPress 当用户在网格中按了任何一个数字键或字母键时,触 发该事件 OnKeyUp 当用户在网格中释放任何被按下的键时,触发该事件 TDBMemo部件主要用于显示和编辑数据库表中的大二进制(BLOB)类型的字段值。TDBMemo部件能够显示多行文本,也允许用户在其中输入和修改多行文本信息,它是Delphi中用来显示和编辑数据库表中的大二进制类型的文本字段的唯一的数据浏览部件。 TDBMemo部件 TDBMemo部件主要用于显示和编辑数据库表中的大二进制(BLOB)类型的字段值。TDBMemo部件能够显示多行文本,也允许用户在其中输入和修改多行 文本信息,它是Delphi中用来显示和编辑数据库表中的大二进制类型的文本字段的唯一的数据浏览部件。 用户必须编程调用CutToClipboard、CopyToClipboard 和PasteFromClipboard方法分别来实现剪切,拷贝和粘贴操作。 TDBImage部件与TDBMemo部件具有很多相似的属性,它是用来显示和编辑数据库表中的BLOB类型的位图图像字段的。 数据浏览部件中的列表框和组合框 在数据浏览部件中有四个部件类似于标准部件中的列表框和组合框,这些列表框和组合框主要是在数据库应用程序中为用户提供一系列的可选择的字段值。注意这些部件只能与TTable部件配合使用,而不能与TQuery部件配合使用。 TDBlistBox 在用户修改当前记录中指定的字段值时,可用该部件显示 一个字段值列表供用户选择 TDBComboBox 把一个TDBEdit部件与一个可选的字段值列表结合在一起, 当用户修改当前记录中的字段时,可以直接从部件中输入 新的字段,也可以打开下拉式列表框选择其中的一个可选项。 TDBLookapList 当用户要编辑修改数据库表当前记录的指定字段时,使用该部件提供多个可选项,这多个可选项是从相关的其它数据库表中读取的,且以列表框的形式提供给用户 TDBLookupCombo 该部件结合了TDBEdit部件和TDBComboBOx部件的功能,用 户可以直接向该部件中输入字段值,也可以从下拉式列表 框中选择一个可选项,只是下拉式列表框中的可选项是从 相关的其他数据库表中读取来的。 注:TDBComboBox部件的一个重要的属性是Items属性,该属性中包含着 TDBComboBox部件在运行过程中下拉式列表框中的可选项,Items中的内容可以在设计阶段指定。 第十七章 SQL编程 使用Delphi 开发的数据库应用中,可以使用SQL语言访问下列三个方面的数据库: ● Paradox或dBASE数据库中的表 在访问这些桌面数据库系统中的数据时,只能使用ANSI标准的SQL语言中的部分SQL 语句,它们主要包括:Select、Insert、Update和Delete语句;即本地SQL语句。有关详细情况请参见附录“局部SQL语句的使用”。 ● 本地InterBase数据库服务器中的数据库 在InterBase数据库中支持的SQL语句, 在Delphi中都可以使用。有关InterBase中SQL语句的语法和限制,请参看“InterBase的语言参考”。 ● 远程数据库服务器中的数据库 当然这要求在Delphi中必须安装相应的SQL Link。只要是数据库服务器上的DBMS支持的SQL语句,在Delphi中都可以使用。有关语法 及限制请参看相关的数据库管理 系统的文档。 TQuery部件使用 1.静态方式是把SQL命令文作为TQuery部件的SQL属性值进行设置,(如果是SQL中的查询命令, 把TQuery部件通过TDataSource部件与数据控制部件相连,查询的结果将会显示在与 TQuery部件相连接的数据浏览部件中)。 动态SQ语句是指SQL语句中包含一些参数变量,在程序中可以为这些参数赋值,在程序运行过程中,各个参数值是变化的。、 2.在SQL编程中使用TQuery部件的具体方法步骤如下: ①为TQuery部件设置DatabaseName属性,它可以是用BDE建立的数据库的别名, 或桌面数据库系统中的目录名或数据库服务器中的文件名, ②为TQuery部件设置SQL属性,TQuery部件的SQL属性值就是应用程序要执行的SQL 命令文本,设置SQL属性有两种方法: ● 在程序设计过程中,我们可以通过对象浏览器(Object Inspector)编辑SQL属性 在Object Inspector中选择SQL属性,这样会打开String List Editor窗口,在其 中我们便可以编写SQL命令,我还可以打开Visual Query Builder来编写SQL命令 (只有Delphi的客户/服务器版本才具有这一工具)。 ● 将SQL命令包含在Pascal代码单元中 在程序运行过程中,首先调用TQuery部件的Close方法关闭当前的TQuery部件,然 后调用Clear方法清除SQL属性,并说明新的SQL命令文本,然后调用Add方法,将新的SQL命令文本加入到SQL属性中。 ③通过调用TQuery部件的Open方法或ExecSQl方法执行 SQL 命令。( Open 方法只执行Select命令,ExecSQL方法还可以执行其它的SQL命令。)(如果使用动态SQL语句,首先调用prepare方法,给动态SQL语句中的参数赋值, 然后再调用Open方法或ExecSQL方法。) 例如,如果我们想查询出表Customer.DB中客户的编号和公司名称, 我们按下列步骤来实现: ①在应用窗体中放置一个TQuery部件、一个TDataSource部件一个TDataGrid部件,并将它们连接起来 ②设置窗体TQuery 部件Query1的DatabaseName属性值为DBDEMOS ③双击Object Inspector窗口中Query1的SQL 属性, Delphi 将显示 String List Editor窗口。 ④在图17.3中的窗口中输入SQL语句: Select CustNo,Company From Custormer; ⑤单击OK按钮,关闭String List Editor窗口。 ⑥设置Query的Open属性为True。 SQL命令文本的编写 静态SQL语句在程序设计时便已固定下来,它不包含任何参数和变量, Select * From Cusromer Where CustNo = 1234; 而动态SQL语句,也被称作参数化的语句,在其中间包含着表示字段名或表名的参数,例如下面的语句是一条动态SQL语句: Select * From Customer Where CustNo =: Number; 在程序运行过程中,要想设置TQuery部件的SQL属性,必须首先调用Close方法,关闭TQuery部件,然后再调用Clear方法清除SQL属性中现存的SQL命令语句, 最后再调用Add方法为SQL属性设置新的SQL命令语句。例如: Query1.Close {关闭Query1) Query1.SQL.Clear {清除SQL属性中的SQL命令语句} Query1.SQL.Add('Select * From Country'); Query1.SQL.Add('Where Name =\"ARGENTINA\" '); 使用Visual Query Builder编写 客户/服务器版本的Delphi还包含一个可视化的查询构造器Visual Query Builder ,用这个可视化的工具我们只能编写Select语句。在应用程序窗体中选择TQuery部件后,单击鼠标右键,弹出一个弹出式菜单,从中选择Run Visual Query Builder后便会弹出一对话框提示你选择要访问的数据库,选择想要访问的数据库之后选择OK按钮,紧接着会出现一个弹出式对话框提示你选择要查询的数据库表,一次可以选择多个数据库表,若要选择多个数据库表,每选择一个表之后单击Add按钮,接着选择另一个表, 选择完要查询的表之后单击Close按钮,这样,可视化的查询构造器中将会显示出用户选择的数据库表。 SQL程序的执行 Open方法只能用来执行SQL语言的查询语句(Select命令), 并返回一个查询结果集,而ExecSQL方法还可以用来执行其它常用的SQL语句(如Insert、UPDATE、 DELETE等命令)。但是程序一般这么写: Try Query1.Open Except Query1.ExecSQL End 在应用程序中使用TQuery部件时,还可以设置它的UniDirectional属性为True,这样会加快检索数据库表的速度, 但是这样只能往一个方向移动记录指针, 在缺省情况下,UniDirectional属性的值为False。 动态SQL语句的编程(又被称为参数化的SQL语句) 在运行过程中,通过程序为参数赋值 用这种方式为参数赋值有三种方法: ①根据参数在SQL语句中出现的顺序,设置TQuery部件的Params属性值为参数赋值。 ②直接根据SQL语句中各参数的名字,调用ParamByName方法来为各参数赋值。 ③将TQuery部件的DataSource属性设置为另一个数据源,这样将另一个数据源中与当前TQuery部件的SQL语句中的参数名相匹配的字段值赋给其对应的参数。(一一明细表) 法一:TQuery部件的SQL语句: Insert Into Customer(CustNo,Name,Country)Values(:CustNo,:Name, : Country) (3个参数) 对于上述这条动态SQL语句中的参数,我们可以利用TQuery部件的params 属性为参数赋值: Query1.params[0].AsString := \"1988\"; Query1.params[1].AsString := \"Lichtenstein\"; Query1.params[2].AsString := \"USA\"; 法二: Query1.ParamByName('CustNo').AsString := \"1988\"; Query1.ParamByName('Name').AsString := \"Lichtenstein\"; Query1.ParamByName('Country').AsString := \"USA\"; 法三:使用Datasource属性为参数赋值。例如: ● 一个TTable部件 名字为Cust,它的DatabaseName属性为DEMOS,TableName属性为Customer。 ● 一个TDatasource部件 名字为Custsource,其Dataset属性被设置为Cust。 ● 一个TQuery部件 名字为ORDERS,其DatabaseName被设置为DEMOS,SQL属性值为: Select Orders.CustNo,Orders.OrderNo,Orders.SaleDate FROM Orders WHERE Orders.CustNo =: CustNo ORDERS的DataSouce属性被设置为CustSource ● 一个TDatasource部件 名字为OrderSource,其DataSet属性被设置为Orders。 ● 两个TDBGrid部件 它们分别连接CustSource和OrderSource。 Prepare方法的使用 常常在窗体的OnCreate事件处理过程中调用prepare方法。然后用上述介绍的方法为参数赋值,最后调用Open方法或ExecSQL方法执行SQL语句,以完成查询。 因而每当一个查询执行完毕之后,要养成调用Unprepare方法以撤消查询的好习惯。在运行程序过程中,通过程序改变TQuery部件的SQL属性值时,Delphi会自动地调用Close方法和Unprepare 方法,以撤消查询。 一个小例子: 执行查询(memo中SQL语句):Query1.close; Query1.SQL.clear; Query1.SQL.Add(Memo1.text); Query1.Open; 清空meomo和sql属性:Query1.close; Query1.SQL.clear; Query1.ExceSQL; 第十八章 Delphi客户服务器应用开发 在数据库环境下,通过若干称作中间件(Middleware)的程序设计接口,客户机可以与服务器通信。这些接口提供应用程序和数据库之间的连通性。 但客户/服务器结构也可以包括多个服务器。然而在这种情况下,每个服务器必定只处理一个不同的数据库或提供一个唯一的服务。(注意:使用两上或多个服务器来处理同一个数据库的结构不认为是客户/服务器系统,相反它是一个分布式数据库系统〕 3步软件: 客户机软件由(网络接口软件、支持用户需求的应用程序以及实现网络能力的实用程序【例如电子邮件(E-Mail)和群件(Groupware)】组成。网络接口软件提供各种数据传输服务。应用程序软件执行具体的任务,如字处理、电子表格和数据库查询生成。实用程序软件通常执行几乎所有网络用户都要求的标准任务。 在识别、评价和选择适当的服务器平台时,必须考虑将由该平台提供的服务。服务器软件既包括遵循于OSI或其它网络结构的网络软件,又包括由该服务器提供给网络上客户机的应用程序或服务软件。 中间件是一个软件层。中间件有好几种类型。它们包括应用程序设计接口(API),远程过程调用(RPC),网络通信、数据库访问以及计算机辅助软件工程(CASE)工具。 1.本地型数据库接口 当用户发出命令,请求DBMS读取数据库中的数据时,该请求首先由工作站(客户)的网络驱动程序处理,它负责把请求从网络上传到所需的服务器网络文件系统。服务器操作系统从适当的磁盘卷上找到数据,并发回等待中的工作站驱动程序。最后,数据回传给DBMS,这样DBMS使用这些数据就象使用本地存储的数据一样。网络情况下的接口比单机情况下接口的处理增加了通信开销,正常情况下这种额外开销不会影响用户的响应时间,除非在网络通信的高峰期间或DBMS要求大数据量传递。 对于本地型DBMS其大部分工作都在工作站一侧完成,即使数据存储在文件服务器上,其对数据的处理仍然要在工作站上进行。这种方式的最主要的一个缺点是无论查询需要多么少的数据,都需要首先将查询中的所有数据通过网络传到工作站,然后由工作站负责选出满足查询条件的数据,不难想象,当几个用户同时操作数据库时,数据库网络的带宽会很快阻塞。 2. 客户/服务器型数据接口 数据库通信接口的工作流程如下: ① 前端应用程序发送命令给数据库通信接口。 ② 接口通过网络把命令传给数据库引擎。 ③ 数据库引擎在服务时上做查询或更新操作之类的工作,通过网络文件系统访问物理数据。 ④ 数据库引擎将结果返送给工作站上的通信接口。 ⑤ 前端从接口上接到结果后,显示或按用户要求做其它处理。 客户/服务器型比本地型DBMS更接近ODBC的原理。因为由前端向数据库的命令发送和由数据库向前端结果的返回都是透明的,并不需知道具体传送方式如何,各系统存在差别地方是:客户/服务器系统在管理工作站和服务器间通信的方式不同, 3.BDE是用于开发客户/服务器数据库应用的理想工具,数据库应用程序既可访问本地数据库又可访问远程数据库。 在Delphi应用程序中访问数据库是通过调BDE的API函数。Delphi在库单元BDE中提供了大约三十多个API函数和各种BDE消息和结构。由于Delphi应用程序的开发是基于部件的,有关BDE API的调用都嵌入了Delphi可视部件类库,因此,建立数据库应用时可以不必管BDE API的细节。只要正确安装IDAPI的Drivers,并进行正确的配置,就能使你的数据库应用程序与服务器连接并访问数据库。 Delphi客户/服务器应用开发环境的构造 Borland SQL Links 的安装 配置SQL环境 与你的BDE应用程序一起安装的有BDE配置工具(BDECFG32.EXE),该工具帮助用户修改他们的应用程序配置。配置参数被存于命名为IDAPI32.CFG的二进制文件中。当应用程序启动时,将读这个文件。通常该文件在应用安装过程中被置于BDE文件目录中(C:\\Program Files\\Common\\BDE)。 在开始配置SQL环境前,必须已完成以下工作: ● 已安装SQL Links软件 ● 退出所有其它Borland应用程序 ● 在Windows 95中打开应用程序组Borland Delphi 2.0 ● 选择IDAPI配置工具图标,出现配置工作窗口后进入驱动程序管理页 Delphi Client/Server编程 下午13:00—17:00 B.实行不定时工作制的员工,在保证完成甲方工作任务情况下,经公司同意,可自行安排工作和休息时间。 3.1.2打卡制度 3.1.2.1公司实行上、下班指纹录入打卡制度。全体员工都必须自觉遵守工作时间,实行不定时工作制的员工不必打卡。 3.1.2.2打卡次数:一日两次,即早上上班打卡一次,下午下班打卡一次。 3.1.2.3打卡时间:打卡时间为上班到岗时间和下班离岗时间; 3.1.2.4因公外出不能打卡:因公外出不能打卡应填写《外勤登记表》,注明外出日期、事由、外勤起止时间。因公外出需事先申请,如因特殊情况不能事先申请,应在事毕到岗当日完成申请、审批手续,否则按旷工处理。因停电、卡钟(工卡)故障未打卡的员工,上班前、下班后要及时到部门考勤员处填写《未打卡补签申请表》,由直接主管签字证明当日的出勤状况,报部门经理、人力资源部批准后,月底由部门考勤员据此上报考勤。上述情况考勤由各部门或分公司和项目文员协助人力资源部进行管理。 3.1.2.5手工考勤制度 3.1.2.6手工考勤制申请:由于工作性质,员工无法正常打卡(如外围人员、出差),可由各部门提出人员名单,经主管副总批准后,报人力资源部审批备案。 3.1.2.7参与手工考勤的员工,需由其主管部门的部门考勤员(文员)或部门指定人员进行考勤管理,并于每月26日前向人力资源部递交考勤报表。 3.1.2.8参与手工考勤的员工如有请假情况发生,应遵守相关请、休假制度,如实填报相关表单。 3.1.2.9 外派员工在外派工作期间的考勤,需在外派公司打卡记录;如遇中途出差,持出差证明,出差期间的考勤在出差地所在公司打卡记录; 3.2加班管理 3.2.1定义 加班是指员工在节假日或公司规定的休息日仍照常工作的情况。 A.现场管理人员和劳务人员的加班应严格控制,各部门应按月工时标准,合理安排工作班次。部门经理要严格审批员工排班表,保证员工有效工时达到要求。凡是达到月工时标准的,应扣减员工本人的存休或工资;对超出月工时标准的,应说明理由,报主管副总和人力资源部审批。 B.因员工月薪工资中的补贴已包括延时工作补贴,所以延时工作在4小时(不含)以下的,不再另计加班工资。因工作需要,一般员工延时工作4小时至8小时可申报加班半天,超过8小时可申报加班1天。对主管(含)以上管理人员,一般情况下延时工作不计加班,因特殊情况经总经理以上领导批准的延时工作,可按以上标准计加班。 3.2.2.2员工加班应提前申请,事先填写《加班申请表》,因无法确定加班工时的,应在本次加班完成后3个工作日内补填《加班申请表》。《加班申请表》经部门经理同意,主管副总经理审核报总经理批准后有效。《加班申请表》必须事前当月内上报有效,如遇特殊情况,也必须在一周内上报至总经理批准。如未履行上述程序,视为乙方自愿加班。 3.2.2.3员工加班,也应按规定打卡,没有打卡记录的加班,公司不予承认;有打卡记录但无公司总经理批准的加班,公司不予承认加班。 3.2.2.4原则上,参加公司组织的各种培训、集体活动不计加班。 3.2.2.5加班工资的补偿:员工在排班休息日的加班,可以以倒休形式安排补休。原则上,员工加班以倒休形式补休的,公司将根据工作需要统一安排在春节前后补休。加班可按1:1的比例冲抵病、事假。 3.2.3加班的申请、审批、确认流程 3.2.3.1《加班申请表》在各部门文员处领取,加班统计周期为上月26日至本月25日。 3.2.3.2员工加班也要按规定打卡,没有打卡记录的加班,公司不予承认。各部门的考勤员(文员)负责《加班申请表》的保管及加班申报。员工加班应提前申请,事先填写《加班申请表》加班前到部门考勤员(文员)处领取《加班申请表》,《加班申请表》经项目管理中心或部门经理同意,主管副总审核,总经理签字批准后有效。填写并履行完审批手续后交由部门考勤员(文员)保管。 3.2.3.3部门考勤员(文员)负责检查、复核确认考勤记录的真实有效性并在每月27日汇总交人力资源部,逾期未交的加班记录公司不予承认。 下午13:00—17:00 度。全体员工都必须自觉遵守工作时间,实行不定时工作制的员工不必打卡。 3.1.2.2打卡次数:一日两次,即早上上班打卡一次,下午下班打卡一次。 3.1.2.3打卡时间:打卡时间为上班到岗时间和下班离岗时间; 3.1.2.4因公外出不能打卡:因公外出不能打卡应填写《外勤登记表》,注明外出日期、事由、外勤起止时间。因公外出需事先申请,如因特殊情况不能事先申请,应在事毕到岗当日完成申请、审批手续,否则按旷工处理。因停电、卡钟(工卡)故障未打卡的员工,上班前、下班后要及时到部门考勤员处填写《未打卡补签申请表》,由直接主管签字证明当日的出勤状况,报部门经理、人力资源部批准后,月底由部门考勤员据此上报考勤。上述情况考勤由各部门或分公司和项目文员协助人力资源部进行管理。 3.1.2.5手工考勤制度 3.1.2.6手工考勤制申请:由于工作性质,员工无法正常打卡(如外围人员、出差),可由各部门提出人员名单,经主管副总批准后,报人力资源部审批备案。 3.1.2.7参与手工考勤的员工,需由其主管部门的部门考勤员(文员)或部门指定人员进行考勤管理,并于每月26日前向人力资源部递交考勤报表。 3.1.2.8参与手工考勤的员工如有请假情况发生,应遵守相关请、休假制度,如实填报相关表单。 3.2 44881 3 11 2625 27 我从来就不是一个独立的人,也从没有独立生活过,直到来了加国。 然后发现,有生俱来的独立细胞瞬间苏醒,几乎可以万事不求人,独立自强到令自己刮目相看。 其实是环境使然,因为我也求不到人,举目无亲,求人不如求己。 一个人带着女儿东奔西走,上下求索,差不多半年的时间,生活才算安定下来。 有幸结识了几位华人朋友,圣诞节前第一次聚餐,说起各自的安居经历,无不感叹,加国是个锻炼人的好地方,堪堪把在座的娇娇女都变成了女汉子。 主人是一位大我两岁的姐姐,上得厅堂下得厨房,最是热情好客,令人宾至如归。 席间说起各自的圣诞计划,我打算带女儿去夏威夷度假。 话音刚落,便有两个声音相继表示可以负责我的机场接送。 我和这里的许多老外一样,早在订机票的同时就租好了机场的昼夜停车,自驾往返机场。于是婉言谢绝了朋友的好意。 “下次不许再这样了啊!知道你是不想给人添麻烦,但你知不知道我们就是喜欢被麻烦呀?”主人心直口快地埋怨道。 “我是早上七点的航班,五点半就得值机,四点半出发,若是让你们送的话,岂不是要跟我一样倒时差了,如果是中午的航班,我就不客气了。” “任何时侯都不需要客气。朋友是用来干什么的?朋友就是用来相互亏欠的。因为把你当朋友,所以我有求于你的时侯才不会犹豫,反之你有需要的时侯,也理所当然地来求我办事,人与人之间的感情就是在一次次的相互亏欠互还人情的过程中日渐亲厚的。我巴不得你麻烦我,这样下次我麻烦你的时侯就理直气壮了,否则你从不求我,我怎么好意思去求你,你说是不是这个理儿?” 我把这当作了一堂宝贵的人情世故课。简单朴实的道理,却蕴含着与人交往的大智慧。 怪不得她周围有这么多的朋友,我很羡慕她为人处事的通透。 从那以后,我学会以另一种方式与人相交,大方索取,大方回报,有欠有还,交情不断。 有位家长临时有事找人代班去图书馆做义工,我正好有时间,立刻响应。之前我们只是恰好在同一个家长群里的点头之交,见面连话都没说过两句。事后,她主动表示有机会一定要替我一次班,我欣然接受,你来我往的便成了朋友,更是将相互代班发扬成了传统。 邻居外出期间托我帮他浇花剪草送收垃圾桶,我爽快地同意,等我回国时,也毫不犹豫地请他为我服务。有一天我不在家,监控摄像头通过手机提示我的院门被风刮开了,摇摇晃晃,还没来得及通知朋友帮我去看一眼,就见邻居走进了画面,拿着工具帮我把松掉的门拴修好,关门离去。我又欠了他一次,没关系,下次包饺子时给他多煮一份。 女儿的玩伴度假回来带给我们一罐锡兰红茶,等到春天,我从国内给她捎回明前龙井。她妈妈种的蓝莓大丰收,送给我一盆,我吃不了做成了蓝莓酱,又给她送回去一瓶。下一次,她干脆叫我去她家,品茶煮蓝莓酱。 几年下来,我不再是当初那个独在异乡求助无门的女汉子,如今女汉子仍在,却是同在异乡,出入相友守望相助。 朋友是用来相互亏欠的,投我以桃,报之以李。 因篇幅问题不能全部显示,请点此查看更多更全内容