其他编程课件_第1页
其他编程课件_第2页
其他编程课件_第3页
其他编程课件_第4页
其他编程课件_第5页
已阅读5页,还剩105页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第10章 其他编程 Delphi实用教程*第1页,共110页。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)连线的 交点,以逆时针方向画弧。 例如,以下的程序将在窗口中将在窗口中绘制一个圆弧: procedure TForm1.FormPa

2、int(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;*第2页,共110页。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窗体上放置一个按钮“

3、连接椭圆上的两点”, 双击该按钮,输入下面的代码: 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; *第3页,共110页。10.1.1画布的通用属性和方法Canvas类的Chord方法示例 *第4页,共110页。10.1.1画布的通用属性和方法(3

4、)Brushcopy方法 语法: Brushcopy(const Dest: TRect;Bitmap: Tbitmap; const Source TRect;Color:Tcolor)Brushcopy方法把位图的一部分复制到画布的某个矩形区域,并用画笔的当前颜色替换位图的颜色。Dest定义画布的一个矩形区域,该矩形用以填充位图,Bitmap定义位图;Source定义位图中的矩形区域,该区域上的位图将被复制;Color定义画笔中,用以替换位图的颜色。 *第5页,共110页。10.1.1画布的通用属性和方法(4)CopyRect方法 语法: CopyRect(Dest:TRect;Canva

5、s:TCanvas;SourceTRect)此方法从另一个画布对象上复制部分图像到该画布。Canvas表示复制画布,Source是源画布上要复制的图像区域,Dest表示目标画布上将接受复制图像的矩形区域。 *第6页,共110页。10.1.1画布的通用属性和方法(5)Draw方法 语法:Draw(x,y:Integer;Graphic:Tgraphic)此方法在画布给定的像素点坐标(x,y)处画由参数Graphic所给的图像,该图像可以是位图、图标或元位图。Tcanvas的其他方法列于表中。 *第7页,共110页。10.1.1画布的通用属性和方法2. Tpen Object(画笔对象) 用于在画

6、布上绘制各种线段,该对象常用的属性有:l Color:定义笔的颜色;l Width:定义线段宽度;l Style:定义线段的各种类型,如表所示; *第8页,共110页。10.1.1画布的通用属性和方法 Mode:定义线段的颜色,取值如表所示。 *第9页,共110页。10.1.1画布的通用属性和方法3. Tbrush Object(画刷对象)画刷对象用以填充图形,如用画刷颜色或图案对矩形或椭圆进行填充。Tbrush拥有一个画刷句柄(Hbrush)。画刷的颜色定义在Color属性中,画刷还有一个Bitmap属性,该属性只能在运行时得到,画刷可使用位图填充图形以产生特殊效果。 *第10页,共110页

7、。10.1.1画布的通用属性和方法4. TColor类型 TColor类型用于定义一个对象的颜色。很多部件的颜色属性就是TColor类型,在Graphics单元中TColor定义如下:TColor=-(COLOR_ENDCOLORS+1)$02FFFFF;*第11页,共110页。10.1.2 图形图像组件 Image组件 Image组件是一个容器组件,它在应用程序窗体窗口中提供了一个矩形区域,用于显示和输出位图、图标、图元文件或用户自定义的图形文件。Image组件的常用属性表。 *第12页,共110页。10.1.2 图形图像组件 2. Shape组件 Shape组件用于在窗体中绘制几何图形,如

8、椭圆、矩形和圆角矩形等。该组件的常用属性有: l Shape:指明需要绘制的几何图形,它可能的取值和含义 如表所示; lBrush:指明在几何图形中填充的样式; l Pen:指定几何图形所使用的线型。 *第13页,共110页。10.1.2 图形图像组件 3. PaintBox组件 该组件是一个简单的画板,它为应用程序提供了可在窗体的特定矩形区域内画图的方法。PaintBox组件的主要属性有: (1) Anchors属性 该属性包含4个子属性(akLeft、akTop、akRight和akBotton),用来指定在运行过程中,当父组件是可调时,它相对于父组件边沿的位置。(2) BoundsRec

9、t属性 该属性用来指定组件的矩形边界,用其父组件的坐标系来表示。 *第14页,共110页。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; ActiveCon

10、trol.BoundsRect:=MyRect;end;(3) Canvas属性 该属性仅在运行时有效,使用该属性可以在组件表面的特定区域进行绘图。 (4) Color属性该属性可用于除“颜色”对话框以外的所有组件或对象。 (5) Constaints属性该属性强制指定组件的大小。 *第15页,共110页。10.1.3图形(Picture)对象 读取图像 读取图像需要使用LoadFromFile方法来调用,同时配合 OpenDialog函数来选择相应的图像文件。下面的代码实现对 图像文件的读取: procedure Tform1.Open1Click(Sender:Tobject); begi

11、n if OpenDialog1.Execute then begin CurrentFile:=OpenDialog1.Filename;Image.Picture.LoadFromFile(CurrentFile); end; end; *第16页,共110页。10.1.3图形(Picture)对象 2. 保存图像 为将Image组件中的图像保存为文件,可调用Image组件的Picture属性的SaveToFile方法。SaveToFile方法需要一个保存文件的文件名。下面的代码是一般程序常用的“Save”和“Save As”菜单的处理程序: procedure Tform1.Save1C

12、lick(Sender:Tobject) beginif 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; *第17页,共110页。10.1.3图形(Picture)对象 3. 替换图像

13、 用户可以在任何进修替换掉Image组件中的图像,只要将一新的图像对象赋给Picture就可以了。下面的代码实现用一个新的位图对象代替原有的Image组件中的Picture中的图像对象的功能:Bitmap:Tbitmap:beginBitmap:=Tbitmap.Create;Bitmap.Width:=NewWidth;Bitmap.Height:=NewHeight;Image.Picture.Graphic:=Bitmap;CurrentFile:=;end; *第18页,共110页。10.1.3图形(Picture)对象 【例】屏幕复制,将当前屏幕的图像抓下来,显示到窗口中;还可以文件

14、的形式保存起来。步骤如下: (1) 建立用户界面:建立窗体Form1,添加一个Panel、一个Timer、 一个SavePictureDialog、四个Button控件并在Panel控件上添加一个 Image控件。 (2) 再创建窗体Form2,用于窗口抓图的显示窗口;在该窗体中添加一个Image控件和Timer控件,其中Image控件用于保存图像。 (3) 设置控件属性:对添加的控件按下表设置其属性。*第19页,共110页。10.1.3图形(Picture)对象 控件的属性设置 *第20页,共110页。10.1.3图形(Picture)对象(4) 激活第一个单元文件,单击Delphi 7的F

15、ile菜单下的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);

16、 / 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);*第21页,共110页。10.1.3图形(Picture)对象 fullscreencanvas.Free; releasedc(0,dc); image1.Picture.Bit

17、map:=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;*第22页,共110页。10.1.3图形(Picture)对象 procedure TForm1.Butto

18、n1Click(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;*第23页,共110页。10.1.3图形(Pict

19、ure)对象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;implementationuses unit3;$R *.dfm*第24页,共110页。10.1.3图形(Picture)对象 procedure TForm2.Timer1Timer(Send

20、er: 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.CopyRec

21、t(rect(0,0,screen.Width,screen.Height), fullscreencanvas,rect(0,0,screen.Width,screen.Height); fullscreencanvas.Free; releasedc(0,dc);*第25页,共110页。10.1.3图形(Picture)对象 image1.Picture.Bitmap:=fullscreen; image1.Width:=fullscreen.Width; image1.Height:=fullscreen.Height; fullscreen.Free; form2.WindowStat

22、e:=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;*第26页,共110页。10.1.3图形(Picture)对象 procedure TForm2.Image1MouseMove(Sender:Tobject;Shift:TShiftState

23、;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*第27页,共110页。10.1.3图形(Picture)对象begin with image1.Canvas do begin moveto(foldx,0); lineto(foldx,screen.He

24、ight); 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;*第28页,共110页。10.1.3图形(Picture)对象 procedure TForm2.Image1MouseDown (Sender:Tobject;Button:TMouseButton;Shift:TShiftState;X,Y:Integer); / 绘制区域

25、图像 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);*第29页,共110页。10.1.3图形(Picture)对象end; x1:=x; y1:=y; oldx:=x; oldy:=y; tr

26、ace:=true; image1.Canvas.Pen.Color:=clblack; image1.Canvas.Brush.Style:=bsclear; end else begin / 第2次点击鼠标,得到矩形,并将它拷贝到FORM1的IMAGE上 x2:=x; y2:=y; trace:=false;*第30页,共110页。10.1.3图形(Picture)对象image1.Canvas.Rectangle(x1,y1,oldx,oldy); width:=abs(x2-x1); height:=abs(y2-y1); orm1.Image1.Width:=width; form1

27、.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

28、;end;end.*第31页,共110页。10.1.3图形(Picture)对象(6) 运行得到如图的结果。 *第32页,共110页。10.2 多媒体编程 10.2.1 简易媒体播放器实例 制作一个媒体播放器,需要在窗体上设置一个TmediaPlayer(该组件位于组件面板的System选项卡上,图标为)、十个Tbutton、一个TopenDialog(位于组件面板的Dialogs选项卡上,图标为)等组件)、一个Edit、一个ComboBox、一个Timer如图所示。各个组件的名字(Name属性)采用默认值。 *第33页,共110页。10.2.1 简易媒体播放器实例该媒体播放器的工作过程是:单

29、击“打开”按钮,就会打开OpenDialog对话框,让用户从中选择一个文件。单击 “播放”按钮,就会播放用户所选择的文件。下面的代码是用于处理Button8的OnClick事件,它将打开媒体播放器。 procedure Tform1.Button8Click(Sender:Tobjict); begin if opendialog1.Execute then begin mediaplayer1.FileName:=opendialog1.FileName; mediaplayer1.open end; end. *第34页,共110页。10.2.1 简易媒体播放器实例为了OpenDialog

30、对话框只列出多媒体文件,需要在属性查看器中设置OpenDialog1的Filter属性,单击打开Filter属性设置旁的按钮,将打开Filter Editor对话框,如图所示,在该对话框中键入所要打开文件的类型,如*.WAV、*.AVI、*.MID等,单击OK。设置好上述内容后,保存该工程,这样一个简单的媒体播放器就制作好了。运行这个程序,打开一个多媒体文件即可。 *第35页,共110页。10.2.2 媒体播放器组件 1. MediaPlayer组件 媒体播放器组件 媒体播放器组件属性 *第36页,共110页。10.2.2 媒体播放器组件2. MediaPlayer组件的属性(1)AutoEn

31、able属性 该属性值是Boolean类型。如果这个属性设为True,媒体播放器在运行过程中能够自动控制哪些按钮当前可用,哪些按钮当前不可用(不可用的按钮以灰色显示)。 (2)AutoOpen属性 该属性值是Boolean类型。如果这个属性设为True,媒体播放器自动打开DeveceType属性指定的多媒体设备(如果DeviceType属性设为dtAutoSelect,媒体播放器将自动打开FileName属性中指定的文件)。 (3)AutoRewind属性 该属性值是Boolean类型,用于设置是否具有自动重绕功能。 *第37页,共110页。10.2.2 媒体播放器组件(4)Capabilit

32、ies属性 该属性值是只读TMPDevCapsSet类型,返回当前设备可以进行 的操作,它的值及值的含义如表所示。 *第38页,共110页。10.2.2 媒体播放器组件(5)ColoredButton属性 该属性值是TbuttonSet集合类型,用于设置哪些按钮彩色显示,哪些按钮用黑白显示,默认时全部按钮均用彩色显示。 *第39页,共110页。10.2.2 媒体播放器组件 MediaPlayer组件的其他属性列于表中。 *第40页,共110页。10.2.2 媒体播放器组件上表Mode属性的取值及含义见表 *第41页,共110页。10.2.2 媒体播放器组件3. MediaPlayer组件的过程

33、和函数 (1)AutoButtonSet过程 该过程用来指定媒体播放器的按钮是否可用。 (2)Back过程 该过程使媒体播放器退回数个帧。 (3)Click过程 这是一个动态过程,该过程决定当OnClick事件被触发时执行什么动作。在默认状态下,当OnClick事件触发时,该过程不招待任何动作,仅仅是调用一个事件处理程序,连接到媒体播放器的OnClick事件处理程序中。该过程可以根据需要重新加载事件处理程序。 (4)Close过程该过程关闭已打开的多媒体播放设备。当应用程序中止时,自动调用该过程。 *第42页,共110页。10.2.2 媒体播放器组件(5)Create函数 这是一个动态的构造函

34、数,该函数可在运行时建立一个 MediaPlayer对象,并对其进行初始化,使得媒体播放器既可 以在设计时静态建立,也可以在运行时通过调用Create方法 动态建立。(6)Destroy函数 这是一个动态的析构函数,该函数用于撤销媒体播放器对象。 应用程序不能直接调用该函数,应先调用Free过程检查媒体播 放器对象是否空闲,如果空闲就释放其占用的内存空间。该函 数执行前,必须确保媒体设备已经关闭。 *第43页,共110页。10.2.2 媒体播放器组件MediaPlayer媒体播放器的其他过程表。 *第44页,共110页。10.2.2 媒体播放器组件 MediaPlayer媒体播放器的其他过程表

35、。*第45页,共110页。10.2.2 媒体播放器组件4. MediaPlayer组件的事件 (1)OnClick事件 当用户移动光标到媒体播放器控制按钮组的任一按钮上,单击鼠标左键或者当媒体播放器控制按钮获得焦点时,单击空格键都将会触发该事件。(2)OnNotify事件 如果Notify属性设置为True,当一个媒体控制方法( 如Back、Close、Eject、Next、Open、Pause、PauseOnly、 Play.Previous、Resume、StartRecording、Step、Stop等)执 行结束时,触发该事件。OnNotify事件触发后,必须重新 设置Notify属性

36、为True,以便触发下一个OnNotify事件。 *第46页,共110页。10.2.2 媒体播放器组件(3)OnPostClick事件 当OnClick事件处理程序被调用以后,触发该事件。(4)OnEnter事件 当一个控件接收到键入焦点时,触发该事件。 *第47页,共110页。10.3 线程 10.3.1 线程概念 所谓多线程,是指操作系统同时运行多个执行体的能力。线程概念与并发性是紧密相关的,多线程的出发点就是为了提高系统的并发度。 线程与进程的差别主要体现在两个方面: 线程和进程虽然都是系统的基本执行单元,线程的划分单位比进程小,因此支持多线程的系统比只支持多进程的系统并发度高;进程将内

37、存作为自己独享的资源,每个进程都有自己的内存空间;而线程共享内存空间,并通过共享内存交换信息,因此有利于提高系统效率。 *第48页,共110页。10.3.2 TThread类 TThread类 TThread类是直接从Tobject继承下来的,它是抽象类,即不能创建TThread类的实例,而只能创建TThread派生类的实例即创建线程对象。 创建线程对象的方法是,选择Delphi 7主菜单下的FileNewOther,在弹出的“New Items”对话框的“New”选项卡中选择Thread Object图标,如图所示。 *第49页,共110页。10.3.2 TThread类 当双击Thread

38、 Object图标后,将出现如图所示的对话框,提示输入 线程对象的名称,线程对象名称是一个标识符,如TestThread。 输入线程对象名后,Delphi 7会自动创建一个包括该线程对象的单 元,该单元给出了线程的框架,其最初的内容如下所示: *第50页,共110页。10.3.2 TThread类unit Unit1;interfaceuses Classes;type TestThread = class(TThread) private Private declarations protected procedure Execute; override;end;implementation

39、 TestThread procedure TestThread.Execute;begin Place thread code here end;end.*第51页,共110页。10.3.2 TThread类TThread派生类中唯一必须覆盖的方法是Excute(),即需要定义线程所执行的功能。 当Create()需要参数为False,则当调用Create()后,线程对象的Execute()方法将会自动被调用,即自动地执行Execute()的代码。当Create()需要参数为False ,则不自动执行Execute()的代码,而是要通过TThread的Resume()方法来唤醒线程。 *第5

40、2页,共110页。10.3.2 TThread类2. 与VCL同步 大多数VCL都要求在任一时刻只允许一个线程访问它,因此在Delphi中使用多线程,还有一个重要的注意事项,即对VCL访问只能在主线程中进行,这表明所有与用户交互的代码只能在主线程中。同时,Delphi为了使线程中的方法也能在主线程中执行,在TThread中设置了一个Synchronize()方法,该方法声明如下:procedure Synchronize(Method:TThreadMethod); Synchronize()方法的参数就是用来传递需要在主线程中执行的线程中的方法。 *第53页,共110页。10.3.3 线程的

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

42、象 For i:=1 to 10000 dobegin If Terminated then break; Value:=Value+1; end;End; *第54页,共110页。10.3.3 线程的终止 【例】创建如图所示的窗体,单击“开始”按钮后,将创建一个附 属线程,该线程执行一个计算任务,与此同时主线程并发执行,用户可在文本区域输入任意的字符。示例中所使用的窗体和组件的属性列于表中,未列的属性均取默认值。 主窗体(设计时) *第55页,共110页。10.3.3 线程的终止 窗体与组件的属性设置 *第56页,共110页。10.3.3 线程的终止保存主窗体单元为Main.pas,源程序如

43、下: 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; *第57页,共110页。10.3.

44、3 线程的终止var MainForm: TMainForm;implementation$R *.dfmprocedure TMainForm.Button1Click(Sender: TObject);begin TTestThread.Create(False); 创建线程,使其立即执行 end;end.*第58页,共110页。10.3.3 线程的终止创建线程单元ThrdU.pas,选择主菜单的FileNewUnit,输入线程对象名为TtestThread,再输入以下源程序:unit ThrdU;interfaceuses Classes;type TTestThread = class

45、(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;*第59页,共110页。10.3.3 线程的终止 TTestThread procedure TTestThread.Execute; 执行一

46、个较长的计算任务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.*第60页,共110页。10.3.3 线程的终止单击F9运行程序,结果如图所示。 *第61页,共110页。10.3.4 线程同步 编写多线程应用程序时,需要控制好线程间的同步资源访问,以保证线程的安全运行。

47、 所谓线程同步,简单说就是协调线程间的执行时序。Win32 API提供了一组同步对象,包括信号量、互斥、临界区和事件等,来解决线程的同步问题。 Delphi分别将事件对象和临界区对象封装为TEvent和TCriticalSection对象,使得事件和临界区更易使用。 *第62页,共110页。10.3.4 线程同步临界区 临界区是指一次只能由一个线程执行的一段代码。在使用 临界区之前,要使用InitializeCriticalSection()过程来初始化它, 其声明如下:procedure InitializeCriticalSection(var lpCriticalSection:TRTL

48、CriticalSection);stdcall; lpCriticalSection是一个TRTLCriticalSection类型的记录, 在该参数中传递未初始化的记录, InitializeCriticalSection()过程就会填充这个记录。 TRTLCriticalSection是一个与临界区资源相关的类型,。 *第63页,共110页。10.3.4 线程同步创建临界区,使用EnterCriticalSection()和LeaveCriticalSection()过程来封装代码块。这两个过程的声明如下:procedure EnterCriticalSection(var lpCrit

49、icalSection: TRTLCriticalSection);stdcall;procedure LeaveCriticalSection(var lpCriticalSection: TRTLCriticalSection);stdcall; 当不再需要TRTLCriticalSection记录时,要调用DeleteCriticalSection()过程将其删除。 *第64页,共110页。10.3.4 线程同步【例】设有一个全局数组,分别用两个线程对其进行两次初始化,需要对这两个线程同步,否则将出现数据不确定的情形。用临界区方式进行两线程的同步,将对数组各元素赋值的代码设为临界区。程序

50、界面如图所示,当单击“初始化”按钮后,将生成两个线程并执行,在列表框中显示数组元素值。 (1)创建应用程序界面,新建如图所示的窗体,并放置一个 label、一个button和一个listbox组件,各组件及其属性设置列于表中。 *第65页,共110页。10.3.4 线程同步窗体与组件的属性设置 *第66页,共110页。10.3.4 线程同步 (2)在Form1对应的Unit1单元文件中输入程序代码: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, For

51、ms, Dialogs, StdCtrls,unit2; Type TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; Label1: TLabel; procedure Button1Click(Sender: TObject); end; *第67页,共110页。10.3.4 线程同步var Form1: TForm1; CS:TRTLCriticalSection; / 声明临界区资源记录变量implementation$R *.dfmprocedure TForm1.Button1Click(Sender: TObje

52、ct);begin InitializeCriticalSection(CS); / 初始化临界区 TInitThread.Create(False); / 创建TinitThread线程对象并执行 TInitThread.Create(False);end;end.*第68页,共110页。10.3.4 线程同步(3)创建线程对象TinitThread,选择主菜单的 FileNewOther,在New Items的New选项卡中双击 “Thread Object”图标,在弹出的对话框中输入线程名 “TinitThread”。(4)在系统自动新建的Unit2单元中输入程序代码: unit Uni

53、t2; interface uses Windows, SysUtils, Classes; / 在此要添加Windows和SysUtils Type以下是TinitThread类定义 TInitThread = class(TThread) protected procedure ShowResult; / 显示结果 procedure Execute; override; end; *第69页,共110页。10.3.4 线程同步implementationuses Unit1; const SIZE=10; / 数组大小var next:integer=0; / 全局变量定义 tag:in

54、teger=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(Ai); DeleteCriticalSection(CS); / 移去临界区 end;end;*第70页,共110页。10.3.4 线程同步procedure TInitThread.Execu

55、te; var i:integer; begin EnterCriticalSection(CS); / 进入临界区 for i:=1 to SIZE do / 为数组各元素赋值begin Ai:=next; Inc(next); Sleep(5); end; LeaveCriticalSection(CS); / 临界区终止 Synchronize(ShowResult);/ 使ShowResult能在主线程中执行end; end.*第71页,共110页。10.3.4 线程同步(5)单击F9运行程序,结果如图所示。 *第72页,共110页。10.3.4 线程同步说明:在第一个线程调用了Ent

56、erCriticalSection()之后,其他的线程就不能进入临界区代码,它们将睡眠;直到第一个线程调用LeaveCriticalSection()后,下一个需要进入临界区的线程才被唤醒。 *第73页,共110页。10.3.4 线程同步2. 互斥 (1)互斥(mutex)与临界区非常相似,但有两个主要区别:互斥可用于不同进程的线程间同步,而临界区不可;互斥可被赋予一个字符串名,通过该名字可创建该互斥对象的 附加句柄。(2)创建互斥对象的函数是CreateMutex(),其原型为 function CreateMutex(lpMutexAttibutes:PsecurityAttributes

57、;bInitialOwner:BOOL;lpName:Pchar):Thandle;stdcall; lpMutexAttibutes参数为一个指向TsecurityAttributes记录的指针,通 常置为0,表示使用默认的安全属性。 BInitialOwner参数用于指出创建互斥对象的线程是否要成为此互斥对 象的拥有者,该参数为false表示互斥对象没有拥有者。 LpName参数指出互斥对象的名称 。*第74页,共110页。10.3.4 线程同步(3)互斥对象不再使用时,应调用CloseHandle()过程来关闭它。当 一个线程不需再拥有互斥对象时,应调用ReleaseMutex()过程。

58、 (4)为了防止其他线程进入同步区代码,需使用aitForSingleObject() 函数,原型为:function WaitForSingleObject(hHandle: Thandle; dwMilliseconds:DWORD):DWAORD;stdcall; DwMilliseconds参数可设为两个值: 当值为0时,函数将只检查由hHandle参数指定的互斥对象是否处 于发信号状态,检查完毕后函数立即返回 当值为INFINITE时,则函数将一直等待,直到信号出现为止 hHandle参数指定的互斥对象 返回值有3种: WAIT_ABANDONED,表明指定对象是互斥对象,并且拥有该

59、 互斥对象的线程在未释放该对象之前就已终止 WAIT_OBJECT_0,表明指定的对象处于发信号状态 WAIT_TIMEOUT,表明等待的时间已过,对象仍是非发信号 状态 *第75页,共110页。10.3.4 线程同步【例】对于临界区的例题,使用互斥方式进行两线程的同步,该应用程序与临界区的例题的差别仅在于线程同步方式不同,其余均相同。程序两个单元文件的内容分别为: / 文件Unit1.pasunit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Di

60、alogs, StdCtrls,Unit2;type TForm1 = class(TForm) Button1: TButton; Label1: TLabel; ListBox1: TListBox; procedure Button1Click(Sender: TObject);end;*第76页,共110页。10.3.4 线程同步var Form1: TForm1; hMutex:THandle=0; / 声明互斥量implementation$R *.dfmprocedure TForm1.Button1Click(Sender: TObject);begin hMutex:=Cre

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论