110
第10第 第第第第 第 10 第 第第第第 Delphi 第第第第

第 10 章 其他编程

  • Upload
    maisie

  • View
    61

  • Download
    4

Embed Size (px)

DESCRIPTION

Delphi 实用教程. 第 10 章 其他编程. 10.1 图形图像处理 10.1.1 画布的通用属性和方法. TCanvas Object (画布对象) 常用方法及功能 : ( 1 ) Arc 方法 ▲语法: Arc(x1,y1,x2,y2,x3,y3,x4,y4:Integer) Arc 方法在椭圆上画一段弧,椭圆由( x1,y1 )、 (x2,y2) 两点所 确定的椭圆所决定。弧的起点是椭圆圆周和椭圆中心与 (x3,y3) 连线的交点。弧矩形终点是椭圆周和椭圆中心与 (x4,y4) 连线的 交点,以逆时针方向画弧。 - PowerPoint PPT Presentation

Citation preview

Page 1: 第 10 章 其他编程

10 第 章 其他编程

第 10 章 其他编程

Delphi 实用教程

Page 2: 第 10 章 其他编程

10 第 章 其他编程

10.1 图形图像处理10.1.1 画布的通用属性和方法

1. TCanvas Object (画布对象) 常用方法及功能 :( 1 ) Arc 方法 ▲ 语法:

Arc(x1,y1,x2,y2,x3,y3,x4,y4:Integer) Arc 方法在椭圆上画一段弧,椭圆由( x1,y1 )、 (x2,y2) 两点所 确定的椭圆所决定。弧的起点是椭圆圆周和椭圆中心与 (x3,y3) 连线的交点。弧矩形终点是椭圆周和椭圆中心与 (x4,y4) 连线的 交点,以逆时针方向画弧。 例如,以下的程序将在窗口中将在窗口中绘制一个圆弧: procedure TForm1.FormPaint(Sender:TObject);

var R:TRect;

begin R:=GetClientRect; Canvas.Arc(R.Left,R.Top,R.Right,R.Bottom,R.Right,R.Top,

R.Left,R.Top); end;

Page 3: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法 ( 2 ) Chord 方法▲ 语法: Chord(x1,y1,x2,y2,x3,y3,x4,y4:Integer) Chord 方法连接椭圆上的两点,椭圆由( x1 , y1 )、 ( x2 , y2 )两点所确定的矩形决定,( x3 , y3 )是始点, ( x4 , y4 )是终点。 例如,在 Form1 窗体上放置一个按钮“连接椭圆上的两点”, 双击该按钮,输入下面的代码: procedure Tform1.Button1Click(Sender:TObject); var R:TRect; beginR:=GetClientRect; {Get coordinates of the current window.} Canvas.Chord(R.Left,R.Top,R.Right,R.Bottom,R.Right, R.Top,R.Left,R.Top); end;

Page 4: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法Canvas 类的 Chord 方法示例

Page 5: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法( 3 ) Brushcopy 方法 ▲ 语法:

Brushcopy(const Dest: TRect;Bitmap: Tbitmap; const Source TRect;Color:Tcolor)Brushcopy 方法把位图的一部分复制到画布的某个矩形区域, 并用画笔的当前颜色替换位图的颜色。●Dest 定义画布的一个矩形区域,该矩形用以填充位图, ●Bitmap 定义位图;●Source 定义位图中的矩形区域,该区域上的位图将被复制;● Color 定义画笔中,用以替换位图的颜色。

Page 6: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法( 4 ) CopyRect 方法 ▲ 语法:

CopyRect(Dest:TRect;Canvas:TCanvas;SourceTRect)此方法从另一个画布对象上复制部分图像到该画布。●Canvas 表示复制画布,●Source 是源画布上要复制的图像区域,●Dest 表示目标画布上将接受复制图像的矩形区域。

Page 7: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法( 5 ) Draw 方法 ▲ 语法:

Draw(x,y:Integer;Graphic:Tgraphic)此方法在画布给定的像素点坐标( x , y )处画由参数Graphic 所给的图像,该图像可以是位图、图标或元位图。Tcanvas 的其他方法列于表中。

Page 8: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法2. Tpen Object (画笔对象)

用于在画布上绘制各种线段,该对象常用的属性有:       Color :定义笔的颜色;

       Width :定义线段宽度; Style :定义线段的各种类型,如表所示;

Page 9: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法● Mode :定义线段的颜色,取值如表所示。

Page 10: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法3. Tbrush Object (画刷对象)

画刷对象用以填充图形,如用画刷颜色或图案对矩形或椭圆进行填充。 Tbrush 拥有一个画刷句柄 (Hbrush) 。画刷的颜色定义在 Color 属性中,画刷还有一个 Bitmap 属性,该属性只能在运行时得到,画刷可使用位图填充图形以产生特殊效果。

Page 11: 第 10 章 其他编程

10 第 章 其他编程

10.1.1 画布的通用属性和方法4. TColor 类型

TColor 类型用于定义一个对象的颜色。很多部件的颜色属性就是TColor 类型,在 Graphics 单元中 TColor 定义如下:TColor=-(COLOR_ENDCOLORS+1)…$02FFFFF;

Page 12: 第 10 章 其他编程

10 第 章 其他编程

10.1.2 图形图像组件 1. Image 组件

Image 组件是一个容器组件,它在应用程序窗体窗口中提供了一个矩形区域,用于显示和输出位图、图标、图元文件或用户自定义的图形文件。 Image 组件的常用属性表。

Page 13: 第 10 章 其他编程

10 第 章 其他编程

10.1.2 图形图像组件 2. Shape 组件

Shape 组件用于在窗体中绘制几何图形,如椭圆、矩形和圆角矩形等。该组件的常用属性有:       Shape :指明需要绘制的几何图形,它可能的取值和含义

如表所示;

     Brush :指明在几何图形中填充的样式;   Pen :指定几何图形所使用的线型。

Page 14: 第 10 章 其他编程

10 第 章 其他编程

10.1.2 图形图像组件 3. PaintBox 组件

该组件是一个简单的画板,它为应用程序提供了可在窗体的特定矩形区域内画图的方法。PaintBox 组件的主要属性有: (1) Anchors 属性 该属性包含 4 个子属性( akLeft 、 akTop 、 akRight 和 akBotton ),用来指定在运行过程中,当父组件是可调时,它相对于父组件边沿的位置。(2) BoundsRect 属性 该属性用来指定组件的矩形边界,用其父组件的坐标系来表示。

Page 15: 第 10 章 其他编程

10 第 章 其他编程

10.1.2 图形图像组件 例如,以下代码用于绘制矩形:procedure Tform1.Button1Click(Sender:TObject);var

MyRect:TRect;begin

MyRect:=ActiveControl.BoundsRect; MyRect.right=MyRect.Left+2*(MyRect.Right-MyRect.Left); MyRect.Botton:=MyRect.Top+(MyRect.Botton-MyRect.Top) div 2; ActiveControl.BoundsRect:=MyRect;

end;(3) Canvas 属性 该属性仅在运行时有效,使用该属性可以在组件表面的特定区域进行绘图。 (4) Color 属性该属性可用于除“颜色”对话框以外的所有组件或对象。 (5) Constaints 属性该属性强制指定组件的大小。

Page 16: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 1. 读取图像 读取图像需要使用 LoadFromFile 方法来调用,同时配合 OpenDialog函数来选择相应的图像文件。下面的代码实现对 图像文件的读取: procedure Tform1.Open1Click(Sender:Tobject); begin if OpenDialog1.Execute then begin CurrentFile:=OpenDialog1.Filename;

Image.Picture.LoadFromFile(CurrentFile); end; end;

Page 17: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 2. 保存图像 为将 Image 组件中的图像保存为文件,可调用 Image 组件的 Picture 属性的 SaveToFile 方法。 SaveToFile 方法需要一个保存文件的文件名。下面的代码是一般程序常用的“ Save” 和“ Save As”菜单的处理程序:

procedure Tform1.Save1Click(Sender:Tobject) begin

if CurrentFile<>’’ then Image.Picture.SaveToFile(CurrentFile)

else SaveAsClick(Sender);end;procedure Tform.Saveas1Click(Sender:TObject);begin

if SaveDialog1.Execute then begin CurrentFile:=SaveDialog1.FileName; Save1Click(Sender); end;

end;

Page 18: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 3. 替换图像

用户可以在任何进修替换掉 Image 组件中的图像,只要将一新的图像对象赋给 Picture 就可以了。下面的代码实现用一个新的位图对象代替原有的 Image 组件中的 Picture 中的图像对象的功能:Bitmap:Tbitmap:begin

Bitmap:=Tbitmap.Create;Bitmap.Width:=NewWidth;Bitmap.Height:=NewHeight;Image.Picture.Graphic:=Bitmap;CurrentFile:=’’;

end;

Page 19: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 【例】屏幕复制,将当前屏幕的图像抓下来,显示到窗口中;还可以文件的形式保存起来。步骤如下: (1) 建立用户界面:建立窗体 Form1 ,添加一个 Panel 、一个 Timer 、

一个 SavePictureDialog 、四个 Button控件并在 Panel控件上添加一个 Image控件。

(2) 再创建窗体 Form2 ,用于窗口抓图的显示窗口;在该窗体中添加一 个 Image控件和 Timer控件,其中 Image控件用于保存图像。 (3) 设置控件属性:对添加的控件按下表设置其属性。

Page 20: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 控件的属性设置

Page 21: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象(4) 激活第一个单元文件,单击 Delphi 7的 File菜单下的 Use Unit项, 出现窗口,选择Unit2 ,单击 OK。(5) 编写程序代码如下 : procedure TForm1.Timer1Timer(Sender: TObject); // 完成对屏幕的复制,并粘帖到 Image控件中 var Fullscreen:Tbitmap; Fullscreencanvas:tcanvas; dc:HDC; begin timer1.Enabled:=false; fullscreen:=tbitmap.Create; // 建立一个 BITMAP 来存放图像 fullscreen.Width:=screen.Width; dc:=getdc(0); // API函数,获取屏幕 fullscreencanvas:=tcanvas.Create;// 建立一个 CANVAS 对象 fullscreencanvas.Handle:=dc; fullscreen.Canvas.CopyRect(rect(0,0,screen.Width,screen.Height), fullscreencanvas,rect(0,0,screen.Width,screen.Height));

Page 22: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 fullscreencanvas.Free;

releasedc(0,dc); image1.Picture.Bitmap:=fullscreen; // 将拷贝下的图像赋给 IMAGE对象 image1.Width:=fullscreen.Width; image1.Height:=fullscreen.Height; fullscreen.Free; form1.WindowState:=wsnormal; form1.Show; messagebeep(1); end; procedure TForm1.Button4Click(Sender: TObject); begin close; end;

Page 23: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 procedure TForm1.Button1Click(Sender: TObject); begin form1.WindowState:=wsminimized; form1.Hide; timer1.Enabled:=true; end; procedure TForm1.Button3Click(Sender: TObject); begin if form1.SavePictureDialog1.Execute then begin form2.Image1.Picture.SaveToFile(savepicturedialog1.FileName); end; end;

Page 24: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象procedure TForm1.Button2Click(Sender: TObject); begin form1.Hide; form2.Hide; form2.Timer1.Enabled:=true; end; end. var Form2: TForm2; foldx,x1,y1,x2,y2,oldx,oldy,foldy:integer;

flag,trace:boolean;implementation

uses unit3;{$R *.dfm}

Page 25: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 procedure TForm2.Timer1Timer(Sender: TObject); var fullscreen:TBitmap;fullscreencanvas:TCanvas;dc:HDC; beginform2.timer1.enabled:=false; fullscreen:=tbitmap.create; fullscreen.width:=screen.Width; fullscreen.Height:=screen.Height; dc:=getdc(0); fullscreencanvas:=tcanvas.Create; fullscreencanvas.Handle:=dc; fullscreen.Canvas.CopyRect(rect(0,0,screen.Width,screen.Height), fullscreencanvas,rect(0,0,screen.Width,screen.Height)); fullscreencanvas.Free; releasedc(0,dc);

Page 26: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 image1.Picture.Bitmap:=fullscreen;

image1.Width:=fullscreen.Width; image1.Height:=fullscreen.Height; fullscreen.Free; form2.WindowState:=wsnormal; form2.Show; messagebeep(1); foldx:=-1; foldy:=-1; image1.Canvas.Pen.Mode:=pmnot; // 笔的模式取反 image1.Canvas.Pen.Color:=clblack; // 笔的颜色 image1.Canvas.Brush.Style:=bsclear; // 刷子的格式 flag:=true; end;

Page 27: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 procedure TForm2.Image1MouseMove

(Sender:Tobject;Shift:TShiftState;X,Y:Integer); begin if trace=true then // 追踪鼠标 begin // 擦除旧的图形并画上新的图形 with image1.Canvas do begin rectangle(x1,y1,oldx,oldy); rectangle(x1,y1,x,y); oldx:=x; oldy:=y; end; end else if flag=true then

Page 28: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象begin with image1.Canvas do begin moveto(foldx,0); lineto(foldx,screen.Height); moveto(0,foldy); lineto(screen.Width,foldy); moveto(x,0); lineto(x,screen.Height); moveto(0,y); lineto(screen.Width,y); foldx:=x; foldy:=y; end; end; end;

Page 29: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象 procedure TForm2.Image1MouseDown (Sender:Tobject;Button:TMouseButton;Shift:TShiftState;X,Y:Integer); // 绘制区域图像 var width,height:integer; newbitmap:TBitmap; begin if(trace=false) then begin // 首次点击鼠标左键,开始追踪鼠标 flag:=false; with image1.Canvas do begin moveto(foldx,0); lineto(foldx,screen.Height); moveto(0,foldy); lineto(screen.Width,foldy);

Page 30: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象end; x1:=x; y1:=y; oldx:=x; oldy:=y; trace:=true; image1.Canvas.Pen.Color:=clblack; image1.Canvas.Brush.Style:=bsclear; end else begin // 第 2次点击鼠标,得到矩形,并将它拷贝到 FORM1 的 IMAGE 上 x2:=x; y2:=y; trace:=false;

Page 31: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象image1.Canvas.Rectangle(x1,y1,oldx,oldy); width:=abs(x2-x1); height:=abs(y2-y1); orm1.Image1.Width:=width; form1.Image1.Height:=height; newbitmap:=Tbitmap.Create; // 生成 Bitmap 对象 newbitmap.Width:=width; newbitmap.Height:=height; newbitmap.Canvas.CopyRect(rect(0,0,width,height),form2.Image1.Canvas,rect(x1,y1,x2,y2)); form1.Image1.Picture.Bitmap:=newbitmap;// 放到 FORM 的 IMAGE 上 newbitmap.Free; form2.Hide; form1.Show; end;end;end.

Page 32: 第 10 章 其他编程

10 第 章 其他编程

10.1.3 图形( Picture )对象(6) 运行得到如图的结果。

Page 33: 第 10 章 其他编程

10 第 章 其他编程

10.2 多媒体编程 10.2.1 简易媒体播放器实例 制作一个媒体播放器,需要在窗体上设置一个 TmediaPlayer(该组件位于组件面板的 System选项卡上,图标为)、十个 Tbutton 、一个 TopenDialog (位于组件面板的 Dialogs选项卡上,图标为)等组件 ) 、一个 Edit 、一个 ComboBox 、一个 Timer如图所示。各个组件的名字( Name 属性)采用默认值。

Page 34: 第 10 章 其他编程

10 第 章 其他编程

10.2.1 简易媒体播放器实例该媒体播放器的工作过程是:单击“打开”按钮,就会打开 OpenDialog 对话框,让用户从中选择一个文件。单击 “播放”按钮,就会播放用户所选择的文件。下面的代码是用于处理 Button8的OnClick事件,它将打开媒体播放器。

procedure Tform1.Button8Click(Sender:Tobjict); begin if opendialog1.Execute then begin mediaplayer1.FileName:=opendialog1.FileName; mediaplayer1.open end; end.

Page 35: 第 10 章 其他编程

10 第 章 其他编程

10.2.1 简易媒体播放器实例为了 OpenDialog 对话框只列出多媒体文件,需要在属性查看器中设置 OpenDialog1 的 Filter 属性,单击打开 Filter 属性设置旁的按钮,将打开 Filter Editor 对话框,如图所示,在该对话框中键入所要打开文件的类型,如 *.WAV、 *.AVI 、 *.MID 等,单击 OK。

设置好上述内容后,保存该工程,这样一个简单的媒体播放器就制作好了。运行这个程序,打开一个多媒体文件即可。

Page 36: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件 1. MediaPlayer 组件

媒体播放器组件

媒体播放器组件属性

Page 37: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件2. MediaPlayer 组件的属性

( 1 ) AutoEnable 属性 该属性值是 Boolean 类型。如果这个属性设为 True ,媒体播放 器在运行过程中能够自动控制哪些按钮当前可用,哪些按钮 当前不可用(不可用的按钮以灰色显示)。

( 2 ) AutoOpen 属性 该属性值是 Boolean 类型。如果这个属性设为 True,媒体播放 器自动打开 DeveceType 属性指定的多媒体设备(如果DeviceType 属性设为 dtAutoSelect ,媒体播放器将自动打开 FileName 属性中指定的文件)。

( 3 ) AutoRewind 属性 该属性值是 Boolean 类型,用于设置是否具有自动重绕功能。

Page 38: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件( 4 ) Capabilities 属性

该属性值是只读 TMPDevCapsSet 类型,返回当前设备可以进行 的操作,它的值及值的含义如表所示。

Page 39: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件( 5 ) ColoredButton 属性

该属性值是 TbuttonSet集合类型,用于设置哪些按钮彩色显示,哪些按钮用黑白显示,默认时全部按钮均用彩色显示。

Page 40: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件 MediaPlayer 组件的其他属性列于表中。

Page 41: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件上表 Mode 属性的取值及含义见表

Page 42: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件3. MediaPlayer 组件的过程和函数

( 1 ) AutoButtonSet过程 该过程用来指定媒体播放器的按钮是否可用。

( 2 ) Back过程 该过程使媒体播放器退回数个帧。

( 3 ) Click过程 这是一个动态过程,该过程决定当 OnClick事件被触发时执 行什么动作。在默认状态下,当 OnClick事件触发时,该过 程不招待任何动作,仅仅是调用一个事件处理程序,连接到 媒体播放器的 OnClick事件处理程序中。该过程可以根据需 要重新加载事件处理程序。

( 4 ) Close过程该过程关闭已打开的多媒体播放设备。当应用程序中止时, 自动调用该过程。

Page 43: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件( 5 ) Create函数

这是一个动态的构造函数,该函数可在运行时建立一个 MediaPlayer 对象,并对其进行初始化,使得媒体播放器既可 以在设计时静态建立,也可以在运行时通过调用 Create 方法 动态建立。( 6 ) Destroy函数

这是一个动态的析构函数,该函数用于撤销媒体播放器对象。 应用程序不能直接调用该函数,应先调用 Free过程检查媒体播 放器对象是否空闲,如果空闲就释放其占用的内存空间。该函 数执行前,必须确保媒体设备已经关闭。

Page 44: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件MediaPlayer媒体播放器的其他过程表。

Page 45: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件 MediaPlayer媒体播放器的其他过程表。

Page 46: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件4. MediaPlayer 组件的事件

( 1 ) OnClick事件 当用户移动光标到媒体播放器控制按钮组的任一按钮上,单 击鼠标左键或者当媒体播放器控制按钮获得焦点时,单击空 格键都将会触发该事件。

( 2 ) OnNotify事件 如果 Notify 属性设置为 True ,当一个媒体控制方法( 如 Back 、 Close 、 Eject 、 Next 、 Open 、 Pause 、 Pa

useOnly 、 Play.Previous 、 Resume 、 StartRecording 、 Step 、 Stop 等)执 行结束时,触发该事件。 OnNotify事件触发后,必须重新 设置 Notify 属性为 True ,以便触发下一个 OnNotify事件。

Page 47: 第 10 章 其他编程

10 第 章 其他编程

10.2.2 媒体播放器组件( 3 ) OnPostClick事件 当 OnClick事件处理程序被调用以后,触发该事件。( 4 ) OnEnter事件 当一个控件接收到键入焦点时,触发该事件。

Page 48: 第 10 章 其他编程

10 第 章 其他编程

10.3 线程 10.3.1 线程概念 所谓多线程,是指操作系统同时运行多个执行体的能力。线程概念与并发性是紧密相关的,多线程的出发点就是为了提高系统的并发度。 线程与进程的差别主要体现在两个方面:

线程和进程虽然都是系统的基本执行单元,线程的划分单位比进程小,因此支持多线程的系统比只支持多进程的系统并发度高;进程将内存作为自己独享的资源,每个进程都有自己的内存空间;而线程共享内存空间,并通过共享内存交换信息,因此有利于提高系统效率。

Page 49: 第 10 章 其他编程

10 第 章 其他编程

10.3.2 TThread 类 1. TThread 类

TThread 类是直接从 Tobject继承下来的,它是抽象类,即不能创建 TThread 类的实例,而只能创建 TThread派生类的实例—即创建线程对象。● 创建线程对象的方法是,选择 Delphi 7主菜单下的

FileNewOther… ,在弹出的“ New Items” 对话框的“ New”选项卡中选择Thread Object 图标,如图所示。

Page 50: 第 10 章 其他编程

10 第 章 其他编程

10.3.2 TThread 类● 当双击 Thread Object 图标后,将出现如图所示的对话框,提示输入

线程对象的名称,线程对象名称是一个标识符,如 TestThread 。

● 输入线程对象名后, Delphi 7 会自动创建一个包括该线程对象的单 元,该单元给出了线程的框架,其最初的内容如下所示:

Page 51: 第 10 章 其他编程

10 第 章 其他编程

10.3.2 TThread 类unit Unit1;interfaceuses Classes; type TestThread = class(TThread) private { Private declarations } protected procedure Execute; override;end;implementation{ }{ TestThread }procedure TestThread.Execute;begin { Place thread code here }end;end.

Page 52: 第 10 章 其他编程

10 第 章 其他编程

10.3.2 TThread 类TThread派生类中唯一必须覆盖的方法是 Excute() ,即需要定义线程所执行的功能。 当 Create() 需要参数为 False ,则当调用 Create()后,线程对象的 Execute() 方法将会自动被调用,即自动地执行 Execute() 的代码。当 Create() 需要参数为 False ,则不自动执行 Execute() 的代码,而是要通过 TThread 的 Resume() 方法来唤醒线程。

Page 53: 第 10 章 其他编程

10 第 章 其他编程

10.3.2 TThread 类2. 与 VCL 同步 大多数 VCL都要求在任一时刻只允许一个线程访问它,因此在 Delphi 中使用多线程,还有一个重要的注意事项,即对 VCL访问只能在主线程中进行,这表明所有与用户交互的代码只能在主线程中。同时, Delphi 为了使线程中的方法也能在主线程中执行,在 TThread 中设置了一个 Synchronize() 方法,该方法声明如下:

procedure Synchronize(Method:TThreadMethod); Synchronize() 方法的参数就是用来传递需要在主线程中执行的线程中的方法。

Page 54: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止 当线程对象的 Execute() 方法执行完毕后,就认为该线程终止了,此时 Delphi会自动调用一个标准例程 EndThread() ,该例程将再调用API函数 ExitThread() ,由 ExitThread() 来清除线程所占用的栈。线程终止时,将触发 OnTerminate事件,可以利用在退出 Execute()之前将 FreeOnTerminate 属性置为 True 的方法来及时清除线程对象。procedure TestThread.Execute;var

i:integer;Begin

FreeOnTerminate := True; //设置 FreeOnTerminate 为 true 以便及时清除线程对象

For i:=1 to 10000 dobegin

If Terminated then break; Value:=Value+1; end;

End;

Page 55: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止 【例】创建如图所示的窗体,单击“开始”按钮后,将创建一个附 属线程,该线程执行一个计算任务,与此同时主线程并发执行,用户可在文本区域输入任意的字符。示例中所使用的窗体和组件的属性列于表中,未列的属性均取默认值。

主窗体(设计时)

Page 56: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止 窗体与组件的属性设置

Page 57: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止●保存主窗体单元为 Main.pas ,源程序如下: unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,ThrdU; type TMainForm = class(TForm) Label1: TLabel; Button1: TButton; Label2: TLabel; Edit1: TEdit; Memo1: TMemo; procedure Button1Click(Sender: TObject); end;

Page 58: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止var MainForm: TMainForm;implementation{$R *.dfm}procedure TMainForm.Button1Click(Sender: TObject);begin TTestThread.Create(False); { 创建线程,使其立即执行 }end;end.

Page 59: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止●创建线程单元 ThrdU.pas ,选择主菜单的 FileNewUnit ,输入线程对象名为 TtestThread ,再输入以下源程序:unit ThrdU;interfaceuses Classes;type TTestThread = class(TThread) { 线程 TTestThread 类定义 } private Answer:integer; protected procedure GiveAnswer; procedure Execute; override;end;implementationuses SysUtils,Main;procedure TTestThread.GiveAnswer;begin MainForm.Edit1.Text:=InttoStr(Answer);end;

Page 60: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止{ TTestThread }procedure TTestThread.Execute; {执行一个较长的计算任务 }Var i:integer;begin FreeOnTerminate:=True; for i:=1 to 2000000 do begin if Terminated then break; Inc(Answer,Round(abs(sin(sqrt(i))))); Synchronize(GiveAnswer); { 使 GiveAnswer 能在主线程中执行 } end;end;end.

Page 61: 第 10 章 其他编程

10 第 章 其他编程

10.3.3 线程的终止● 单击 F9运行程序,结果如图所示。

Page 62: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步 编写多线程应用程序时,需要控制好线程间的同步资源访问,以保证线程的安全运行。 所谓线程同步,简单说就是协调线程间的执行时序。Win32 API提供了一组同步对象,包括信号量、互斥、临界区和事件等,来解决线程的同步问题。 Delphi 分别将事件对象和临界区对象封装为 TEvent 和 TCriticalSection 对象,使得事件和临界区更易使用。

Page 63: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步1. 临界区

◆临界区是指一次只能由一个线程执行的一段代码。在使用 临界区之前,要使用 InitializeCriticalSection()过程来初始化它, 其声明如下:

procedure InitializeCriticalSection(var lpCriticalSection:TRTLCriticalSection);stdcall;

● lpCriticalSection 是一个 TRTLCriticalSection 类型的记录, 在该参数中传递未初始化的记录, ● InitializeCriticalSection()过程就会填充这个记录。 ● TRTLCriticalSection 是一个与临界区资源相关的类型,。

Page 64: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步◆创建临界区,使用 EnterCriticalSection() 和 LeaveCriticalSection()过程来封装代码块。这两个过程的声明如下:procedure EnterCriticalSection(var lpCriticalSection: TRTLCriticalSection);stdcall;procedure LeaveCriticalSection(var lpCriticalSection: TRTLCriticalSection);stdcall; ◆当不再需要 TRTLCriticalSection记录时,要调用 DeleteCriticalSection()过程将其删除。

Page 65: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步【例】设有一个全局数组,分别用两个线程对其进行两次初始化,需要对这两个线程同步,否则将出现数据不确定的情形。用临界区方式进行两线程的同步,将对数组各元素赋值的代码设为临界区。程序界面如图所示,当单击“初始化”按钮后,将生成两个线程并执行,在列表框中显示数组元素值。

( 1 )创建应用程序界面,新建如图所示的窗体,并放置一个 label 、一个 button 和一个 listbox 组件,各组件及其属性设置列于表中。

Page 66: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步窗体与组件的属性设置

Page 67: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步 ( 2 )在 Form1 对应的 Unit1 单元文件中输入程序代码:

unit Unit1; interface uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls,unit2; Type

TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; Label1: TLabel; procedure Button1Click(Sender: TObject);

end;

Page 68: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步var

Form1: TForm1; CS:TRTLCriticalSection; // 声明临界区资源记录变量

implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);begin

InitializeCriticalSection(CS); // 初始化临界区 TInitThread.Create(False); // 创建 TinitThread 线程对象并执行 TInitThread.Create(False);

end;end.

Page 69: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步( 3 )创建线程对象 TinitThread ,选择主菜单的

FileNewOther… ,在 New Items 的 New选项卡中双击 “Thread Object” 图标,在弹出的对话框中输入线程名 “TinitThread” 。( 4 )在系统自动新建的 Unit2 单元中输入程序代码:

unit Unit2; interface uses Windows, SysUtils, Classes;

// 在此要添加Windows 和 SysUtils Type

{ 以下是 TinitThread 类定义 } TInitThread = class(TThread) protected procedure ShowResult; // 显示结果 procedure Execute; override; end;

Page 70: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步implementationuses Unit1; const SIZE=10; // 数组大小var next:integer=0; // 全局变量定义 tag:integer=0; A:array [1..SIZE] of integer; procedure TInitThread.ShowResult; var i:integer; begin inc(tag); if tag=2 then begin // 两个线程均执行完毕 for i:=1 to SIZE do //在列表框中显示数组各元素值 Form1.ListBox1.Items.Add(intToStr(A[i])); DeleteCriticalSection(CS); // 移去临界区 end;end;

Page 71: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步procedure TInitThread.Execute; var i:integer; begin EnterCriticalSection(CS); // 进入临界区 for i:=1 to SIZE do // 为数组各元素赋值

begin A[i]:=next; Inc(next); Sleep(5); end; LeaveCriticalSection(CS); // 临界区终止 Synchronize(ShowResult); // 使 ShowResult 能在主线程中执行

end; end.

Page 72: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步( 5 )单击 F9运行程序,结果如图所示。

Page 73: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步说明:

在第一个线程调用了 EnterCriticalSection()之后,其他的线程就不能进入临界区代码,它们将睡眠;直到第一个线程调用 LeaveCriticalSection()后,下一个需要进入临界区的线程才被唤醒。

Page 74: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步2. 互斥

(1)互斥( mutex )与临界区非常相似,但有两个主要区别:●互斥可用于不同进程的线程间同步,而临界区不可;●互斥可被赋予一个字符串名,通过该名字可创建该互斥对象的 附加句柄。(2)创建互斥对象的函数是 CreateMutex() ,其原型为 function CreateMutex(lpMutexAttibutes:PsecurityAttributes;bInitialOwner:BOOL;lpName:Pchar):Thandle;stdcall;

● lpMutexAttibutes 参数为一个指向 TsecurityAttributes记录的指针,通 常置为 0 ,表示使用默认的安全属性。 ● BInitialOwner 参数用于指出创建互斥对象的线程是否要成为此互斥对

象的拥有者,该参数为 false 表示互斥对象没有拥有者。● LpName 参数指出互斥对象的名称 。

Page 75: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步(3)互斥对象不再使用时,应调用 CloseHandle()过程来关闭它。当 一个线程不需再拥有互斥对象时,应调用 ReleaseMutex()过程。

(4) 为了防止其他线程进入同步区代码,需使用 aitForSingleObject() 函数,原型为:function WaitForSingleObject(hHandle: Thandle; dwMilliseconds:DWORD):DWAORD;stdcall;

● DwMilliseconds 参数可设为两个值: ①当值为 0 时,函数将只检查由 hHandle 参数指定的互斥对象是否处 于发信号状态,检查完毕后函数立即返回 ②当值为 INFINITE 时,则函数将一直等待,直到信号出现为止 ● hHandle 参数指定的互斥对象 ●返回值有 3 种: ①WAIT_ABANDONED ,表明指定对象是互斥对象,并且拥有该 互斥对象的线程在未释放该对象之前就已终止 ②WAIT_OBJECT_0 ,表明指定的对象处于发信号状态 ③WAIT_TIMEOUT ,表明等待的时间已过,对象仍是非发信号 状态

Page 76: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步【例】对于临界区的例题,使用互斥方式进行两线程的同步,该应用程序与临界区的例题的差别仅在于线程同步方式不同,其余均相同。程序两个单元文件的内容分别为: // 文件 Unit1.pasunit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,Unit2;type TForm1 = class(TForm) Button1: TButton; Label1: TLabel; ListBox1: TListBox; procedure Button1Click(Sender: TObject);end;

Page 77: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步var Form1: TForm1; hMutex:THandle=0; // 声明互斥量implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);begin hMutex:=CreateMutex(nil,False,nil); // 创建互斥量 TInitThread.Create(False); // 创建 TinitThread 线程对象并执行 TInitThread.Create(False);end;end.

Page 78: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步//文件 Unit2.pasunit Unit2;interfaceuses Windows, SysUtils,Classes;type TInitThread = class(TThread) protected procedure ShowResult; // 显示结果 procedure Execute; override;end;

Page 79: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步 implementation uses Unit1; const SIZE=10; // 数组大小 var next:integer=0; // 全局变量定义 tag:integer=0; A:array [1..SIZE] of integer; procedure TInitThread.ShowResult; var i:integer; begin inc(tag); if tag=2 then begin { 两个线程均执行完毕 } for i:=1 to SIZE do // 在列表框中显示数组各元素值 Form1.ListBox1.Items.Add(intToStr(A[i])); CloseHandle(hMutex); // 关闭互斥对象 end; end;

Page 80: 第 10 章 其他编程

10 第 章 其他编程

10.3.4 线程同步procedure TInitThread.Execute;var i:integer;begin if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0 then { 此时,若要拥有 hMutex互斥对象的线程将睡眠,用来禁止其他线程进入此同步区域的代码 } begin for i:=1 to SIZE do // 为数组各元素赋值 begin A[i]:=next; Inc(next); Sleep(5); end; end; ReleaseMutex(hMutex); // 释放互斥量 Synchronize(ShowResult); // 使 ShowResult 能在主线程中执行end;end.

Page 81: 第 10 章 其他编程

10 第 章 其他编程

10.4 DLL 应用和开发 DLL DLL ( Dynamic Link Library ),即动态链接库,它就是程序模块,包括编译过的可执行代码、数据或资源,能够被其他的Windows 应用程序共享。大部分 DLL 文件的扩展名为 .dll ,也有的可能是 .drv (设备驱动程序)、 .sys (系统文件)或 .fon (字体文件)。Windows系统文件 Kernel32.dll 、 User32.dll 、 GDI32.dll 就是核心 Win32系统的动态链接库

Kernel.dll负责内存、进程和线程的管理User32.DLL负责创建窗口和处理Win32消息GDI32.DLL负责处理图形。

DLL 和可执行文件( exe )非常类似,但 DLL 中包含了可执行代码却不能单独执行,而应由 Windows 应用程序直接或间接调用。

Page 82: 第 10 章 其他编程

10 第 章 其他编程

10.4.1 使用 DLL 的优点 1. 节省资源

动态链接不将所调用的函数代码拷贝到应用程序的可执行文件 中,而是应用程序运行时,才动态地装载 DLL ,其代码将被映 射到进程的地址空间中,当要执行所调用 DLL 中的函数时,根 据链接产生的重定位信息,转去执行 DLL 中相应的函数代码。 2. 共享代码、资源和数据

把资源组织到 DLL 中,就可以让许多应用程序使用,而不必在内 存中重复装入这些内容。线程是相互独立的所有线程可以共享 DLL 的数据 。 3. 实现模块化

可将程序划分为多个 DLL模块,既可以提高模块化程度,又可以 隐蔽代码实现细节。

Page 83: 第 10 章 其他编程

10 第 章 其他编程

10.4.1 使用 DLL 的优点4. 独立于编程语言 在一种开发环境下设计的 DLL 程序,可以在其他的环境中使用。5. 便于系统升级

如果需对系统升级,只要将所涉及的 DLL 进行即可,而不必将 整个系统重新编译、链接,减少了工作量。

Page 84: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL 创建 DLL 的步骤是:首先创建一个新的 DLL项目(如 project1 ),文件头部为:

LibraryProject1; // Project1 为创建的项目名 在所创建的项目的 Uses语句中加入 Exports语句,指明使用 DLL 的应用程序要调用的函数或过程名。形式为:

exports // 引出函数名或过程名 函数名 name '函数引用名 '; // 函数名与函数引用名通常取为相同函数引用名是使用该 DLL 文件的应用程序声明引用 DLL函数或过程时的名字。在 DLL 单元文件( .Pas 文件)中加入 DLL 的函数或过程的声明,形式如下:函数名 ( 参数表 ) :类型名 ;stdcall; // 过程与之类似

如在另一个 pas 文件中说明和定义的 ,则要在 DLL项目文件中加入以下语句: Uses DllEXP in 'DllEXP.pas' {Form1};对项目进行编译即形成 DLL 文件,可被其它项目调用。

Page 85: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL 【例】本例创建一个 DLL ,文件名为 Max.dll ,其中包含一个求两个数中的大者的函数 MaxNum 。再设计一个主程序调用 DLL中的函数在主程序中输入两个整数,通过调用该 DLL ,即可求出较大的数。

1 )创建 Max.dll 文件 ( 1 )新建一个 DLL项目。选择主菜单的 FileNewOthers…菜

单项,在“ New Items” 对话框中双击“ DLL Wizard”图标,单 击 OK 按钮。 ( 2 )在所弹出的代码编辑窗口中输入 DLL 文件的程序代码,该 DLL 的程序代码如下:

Page 86: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLLlibrary Max; // DLL项目名为 Maxuses SysUtils, Classes;{$R *.res}function MaxNum(Num1,Num2:integer):integer;stdcall; // 定义求最大值函数begin if Num1>Num2 then result:=Num1 else result:=Num2;end;exports MaxNum name 'MaxNum'; // 引出求最大值函数 end.

Page 87: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL( 3 )选择主菜单下的 FileSave命令项,保存该文件名为

Max.dpr 。 ( 4 )选择主菜单下的 ProjectCompile Max (或用 Ctrl+F9 快捷键)菜单项,对 Max.dpr 进行编译,即生成 Max.dll 文件。2 )调用 DLL创建一个应用程序调用 Max.dll 文件中的 MaxNum函数。该应用程 序的界面如图所示,所使用的组件及其属性见下一页表中。

Page 88: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL窗体与组件的属性设置

Page 89: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL主程序对应的单元文件为 Unit1.pas 文件,其内容如下: unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type

Page 90: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Label3: TLabel; Edit1: TEdit; Edit2: TEdit; Label4: TLabel; Edit3: TEdit; Button1: TButton; procedure Button1Click(Sender: TObject);end;var Form1: TForm1;implementation{$R *.dfm}

Page 91: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLLfunction MaxNum(Num1,Num2:integer):integer;stdcall;external 'Max.dll' name 'MaxNum';

// 对 DLL函数进行外部声明procedure TForm1.Button1Click(Sender: TObject);var

N1,N2:integer; MX:integer;

begin N1:=strtoint(Edit1.Text); N2:=strtoint(Edit2.Text); MX:=MaxNum(N1,N2); // 调用 DLL函数 Edit3.Text:=inttostr(MX);

end;end.

Page 92: 第 10 章 其他编程

10 第 章 其他编程

10.4.2 创建 DLL程序的运行结果如图所示。

Page 93: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL 1. 装载时调用( Load-time Dynamic Linking )

在应用程序编译之前已经明确知道要调用 DLL 的哪些函数或过程,在编译时目标文件中只保留必要的链接信息;应用程序执行时,利用链接信息加载 DLL函数或过程代码,并在内存中将 DLL 代码链接到调用程序的执行空间中。 在调用 DLL 的应用程序单元文件中,需要在 Implementation之后对 DLL函数进行外部声明,形式如下:

Implementation function 函数名(参数表):类型名; stdcall ; External 'DLLName'; 装载时调用 DLL 程序执行速度快,效率高。缺点是如果加载的 DLL不存在或 DLL 中没有要调用的函数或过程,应用程序就会自动终止运行。 DLL 程序一旦加载就一直驻留在应用程序地址空间。

Page 94: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL2. 运行时调用( Run-time Dynamic Linking )编译时并不知道将会调用 DLL 的哪些函数或过程 。 在运行时用Windows 的 API函数 LoadLibary 和 GetProcAddress函数动态地获得 DLL函数或过程的入口地址,再使用 FreeLibary进行释放。设要调用的 DLL 中包含一个名为 test 的函数:function test (参数表):类型名; stdcall ;运行时调用 DLL 的方法是:( 1 )在调用该 DLL 的应用程序的 Type 类型声明处加入如下 定义:

type Ttest = function (参数表):类型名;( 2 )在 Var变量定义部分定义如下变量: VAR Aptr:Ttest;

Ihnd:Thandle; RetVal: 类型名 ; 其中 Aptr 、 Ihnd 两个变量必须定义, RetVal 是 DLL函数的返回 值,视具体情况而定。

Page 95: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL( 3 )在调用 DLL 处加入以下的语句进行 DLL装载: Ihnd:=LoadLibrary ( ' 路径: DLL 文件名 '); Aptr:=GetProcAddress ( Ihnd ,函数名);( 4 )在应用程序需要之处调用 DLL函数: RetVal:=Test ( Aptr )(实参表);( 5 )调用完后,要用 FreeLibrary释放 DLL占用的内存: FreeLibary ( Ihnd );

Page 96: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL 【例】本例创建一个 DLL ,文件名为 MyCalendar.dll ,其中包含一个显示星期的函数 ShowCalendar ,再设计一个主程序以运行时调用方式调用该 DLL 中的此函数。

1 )创建 MyCalendar.dll (1) 新建一个 DLL项目。 (2) 在所弹出的代码编辑窗口中输入 如下 DLL 文件的程序代码: // 文件名为 MyCalender.dpr; 编译此文件生成MyCalendar.dll library MyCalendar; uses SysUtils, Classes,Unit1 in 'Unit1.pas'{Form1}; {$R *.res} Exports ShowCalendar name 'ShowCalendar'; // 声明 DLL函数 begin end.

Page 97: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL(3) 选择主菜单下的 FileNewForm ,新建一个窗体,在其中放

置一个 Tcalendar 组件(该组件位于组件面板的 Samples选项 卡上,图标为 )和一个 Bevel 组件,所设计的窗体如图 所示,所使用的组件及其属性列于下一页表中。

Page 98: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL窗体与组件的属性设置

Page 99: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL(4) 在第 3步所建窗体所对应的单元文件中输入程序代码。 以下是 Unit1.pas 文件的源程序代码:

unit Unit1; interface uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, Buttons, StdCtrls, ComCtrls, Grids, Calendar, Spin, ExtCtrls;type

TCalForm = class(TForm) // 窗体定义 Calendar1: TCalendar; Bevel1: TBevel; Label1: TLabel; EditYear: TEdit; CMBMonth: TComboBox; Label2: TLabel;

Page 100: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL btnOK: TBitBtn;

btnCancel: TBitBtn; procedure FormCreate(Sender: TObject); procedure CMBMonthChange(Sender: TObject); procedure EditYearChange(Sender: TObject); procedure EditYearKeyPress(Sender: TObject; var Key: Char); procedure btnOKClick(Sender: TObject); procedure btnCancelClick(Sender: TObject); end;

Page 101: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL// 声明要引出的函数function ShowCalendar(AHandle:THandle;ACaption:String):TDateTime;stdCall; implementation{$R *.dfm}procedure TCalForm.FormCreate(Sender: TObject); //窗体创建事件var i:integer;begin for i:=Low(LongMonthNames) to High(LongMonthNames) do CMBMonth.Items.Add(LongMonthNames[i]); CMBMonth.ItemIndex:=Calendar1.Month-1; EditYear.Text:= IntToStr(Calendar1.Year);end;

Page 102: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLLprocedure TCalForm.CMBMonthChange(Sender: TObject);//ComboBox事件begin Calendar1.Month:=(Sender as TComboBox).ItemIndex+1;end;procedure TCalForm.EditYearChange(Sender: TObject); //Edit事件begin Calendar1.Year:=StrToInt((Sender as TEdit).Text);end;procedure TCalForm.EditYearKeyPress(Sender: TObject; var Key: Char);begin if (not (Key in ['0'..'9'])) and (ord(Key)<>VK_BACK) then //若输入的非数字键或键 begin Key:=#0; Beep; //振铃响 end;end;

Page 103: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLLprocedure TCalForm.btnOKClick(Sender: TObject);begin close;end;procedure TCalForm.btnCancelClick(Sender: TObject);begin CMBMonth.ItemIndex:=Calendar1.Month-1; EditYear.Text:= IntToStr(Calendar1.Year);end;

Page 104: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLLfunction ShowCalendar(AHandle:THandle;ACaption:String):TDateTime; //引出函数定义var CalForm: TCalForm; //DLL 窗体Begin //复制应用程序的句柄给 DLL 的 TApplication 对象 Application.Handle:=AHandle; CalForm:=TCalForm.Create(Application); // 创建并显示窗体 try CalForm.Caption:=ACaption; //窗体标题 CalForm.ShowModal; //显示方式为模式化 Result:=CalForm.Calendar1.CalendarDate; // 返回设定的日期 finally CalForm.Free; //卸载窗体 end;end;end.

Page 105: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL( 5 )选择主菜单下的 Save命令项,保存该文件名为 Unit1.dpr 。( 6)选择主菜单下的 ProjectCompile MyCalendar菜单项,编译生 成MyCalendar.dll 。 2 )调用 DLL 创建一个应用程序调用 MyCalendar.dll 文件中的 ShowCalendar函数,程序的功能是,当用户设置某一日期后,该日期将被返回给本程序显示 ,界面如图。

Page 106: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL程序对应的单元文件为 Test.pas 文件,其内容如下:unit test;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons;Type // 定义一个过程数据类型 TShowCalendar

TShowCalendar=function(AHandle:THandle;ACaption:String):TDateTime;stdcall;

TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; BitBtn1: TBitBtn; procedure BitBtn1Click(Sender: TObject);end;var Form1: TForm1;implementation{$R *.dfm}

Page 107: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLLprocedure TForm1.BitBtn1Click(Sender: TObject);var AHandle:THandle; ShowCalendar:TShowCalendar;begin AHandle:=LoadLibrary('MyCalendar.dll'); // 动态载入 DLL ,返回其句柄 try if AHandle<>0 then // 载入成功 // 获得函数 SHowCalendar 的地址,@为取址运算 @ShowCalendar:=GetProcAddress(AHandle,'ShowCalendar'); if not (@ShowCalendar=nil) then // 找到 ShowCalendar函数 // 在 Edit1 上显示设定的日期 Edit1.Text:=DateToStr(ShowCalendar(Application.Handle,‘调用 DLL 显示 ')) else RaiseLastWin32Error; finally FreeLibrary(AHandle); end; end; end.

Page 108: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL单击 F9运行程序,程序主窗体如图 10.15 所示,

单击其中的“加载”按钮,将弹出 DLL 窗体,如下页图所示,

Page 109: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL

在该窗体中设置年和月份值后,单击“设置”按钮,该窗口将被释放,而所设置的年、月和日将在主窗体的 Edit框中显示,如下页图所示。

Page 110: 第 10 章 其他编程

10 第 章 其他编程

10.4.3 调用 DLL