2023年6月22日发(作者:)
Delphi回调函数及线程使⽤回调函数原因:在写线程时,⽤beginThread函数和creatthread函数可以实现函数调⽤及被调⽤函数的参数传递(⽤⼀个结构体,或数组进⾏参数传递)。在⽤线程类的时候,⽤回调函数的⽅法时,没法传递被调⽤函数参数,故写此⽂。下⽂⾃⼰的demo,测试传递readCount数值Delphi回调函数及其使⽤1 回调函数的概述回调函数是这样⼀种机制:调⽤者在初始化⼀个对象(这⾥的对象是泛指,包括OOP中的对象、全局函数等)时,将⼀些参数传递给对象,同时将⼀个调⽤者可以访问的函数地址传递给该对象。这个函数就是调⽤者和被调⽤者之间的⼀种通知约定,当约定的事件发⽣时,被调⽤者(⼀般会包含⼀个⼯作线程)就会按照回调函数地址调⽤该函数。这种⽅式,调⽤者在⼀个线程,被调⽤者在另⼀个线程。消息:消息也可以看作是某种形式的回调,因为消息也是在初始化时由调⽤者向被调⽤者传递⼀个句柄和⼀个消息编号,在约定的事件发⽣时被调⽤者向调⽤者发送消息。 这种⽅式,调⽤者在主线程中,被调⽤者在主线程或者⼯作线程中。Delphi事件模型:在Delphi的VCL中有很多可视化组件都是使⽤事件模型,例如TForm的OnCreate事件,其原理是:在设计时指定事件函数,在运⾏时事件触发,则会调⽤在设计时指定的事件函数。在机制上,Delphi事件模型与回调是⼀样的。但具体形式有些区别,纯的回调函数是全局函数的形式,⽽Delphi事件是对象⽅法的形式,即可以定义如下回调函数类型 typeTCallBackFunc = procedure (pData: Pointer) of object;2 回调函数的使⽤说明回调函数主要在两个场合使⽤,第⼀个是某些Windows的API要求⽤回调函数作为其参数地址,另⼀种是⽤户在某种特定的场合定义的某个函数需要使⽤回调函数作为其参数地址,对于⽤户的定义的函数来说,⼀般是当调⽤动态连接库中的函数时使⽤。对于使⽤⼀个回调函数主要有以下⼏个步骤:1、定义⼀个回调函数类型,跟⼀般的函数过程的定义并没有什么区别,但其定义必须根据需要满⾜回调函数的函数要求,唯⼀的区别在于在函数或过程的定义后⾯必须声明其为windows标准调⽤;例:typeTHDFunction= function(I:integer;s:string):integer; stdcall;对于过程的声明:typeTHDProcedure=procedure(s:string); stdcall;2、 然后根据此原形定义⼀个相应的函数或过程,对于这个函数或过程来说名字没有什么要求,对函数其参数的类型和返回值的类型必须和定义的回调函数类型完全⼀致,对于过程来说,只需要其参数类型⼀样就可以了。例:根据上⾯的函数和过程的原形定义⼀个相应的函数和⼀个相应的过程。函数原形定义:Function HdFunExample(k:integer,sExam:string):integer; stdcall;过程定义:procedure HdProExample(sExam:string);stdcall;3、 在程序中实现此回调函数或着过程;Function HdFunExample(k:integer,sExam:string):integer; stdcall;BeginEnd;procedure HdProExample(sExam:string);stdcall;beginend;4、 调⽤过程;回调函数⼀般作为系统的某个函数的⼊⼝地址;根据调⽤函数的原形:假设有如下调⽤函数:function DyHdFunExample(HdFun:THDFunction;I:integer):boolean;注:在调⽤函数中通过对函数指针的处理可以直接调⽤回调函数(即调⽤函数中的那个是回调函数类型的参数,直接操作它),使回调函数履⾏⼀定的操作。即在调⽤函数中实现回调函数的功能。调⽤:varI:integer;beginI:=DyHdFunExample(@HdFunExample,i);//…….End;3 举例说明⽰例程序在H:/ 回调函数⽰例/ ⽬录下⾯。回调函数的使⽤主要在于Windows原有的API函数,但对于⽤户的⾃定义的调⽤函数⼀般在于动态连接库中。常规的同⼀个⼯程下⾯⼀般不需要使⽤回调函数。(个⼈认为).。功能⼤体描述:Form1中有⼀个Edit和⼀个Button,当点击BUTTON时弹出FORM2,FORM2中也有⼀个EDIT和⼀个BUTTON,当点击FORM2中的BUTTON时,将FORM2中的EDIT的TEXT属性赋值给FORM1中的EDIT的TEXT。unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs,StdCtrls;typeTForm1 = class(TForm){主窗体中放⼀个Edit和⼀个Button}Edit1: TEdit;Button1: TButton;procedure Button1Click(Sender: TObject);private{ Private declarations }{定义⼀个⽤于回调的过程}procedure test(str:string);public{ Public declarations }end;varForm1: TForm1;implementation{引⽤unit2}uses unit2;{$R *.dfm}{回调过程的实现部分}procedure (str: string);begin{将str值副给Edit1}:=str;end;procedure 1Click(Sender: TObject);begin{调⽤Unit2的接⼝⽅法}CallUnit2(test);end; Unit2;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;type{定义⼀个回调函数类型}TFuncCallBack=procedure(str:string) of object;TForm2 = class(TForm){Form2中也有⼀个Edit和⼀个Button}Edit1: TEdit;Button1: TButton;procedure Button1Click(Sender: TObject);private{ Private declarations }{定义⼀个回调函数类型的变量}aFuncCallBack:TFuncCallBack;public{ Public declarations }end;{提供给Unit1调⽤的接⼝⽅法,注意⾥⾯的参数的类型}procedure CallUnit2(FuncCallBack:TFuncCallBack);varForm2: TForm2;implementation{$R *.dfm}{接⼝⽅法的实现部分}procedure CallUnit2(FuncCallBack:TFuncCallBack);Form(TForm2,Form2);{将参数赋值给FuncCallBack}allBack:=FuncCallBack;dal;end;procedure 1Click(Sender: TObject);begin{当点击Form2的按钮时将Form2中的Edit的值传递给了Form1中的Edit}{是不是很神奇?我并没有uses Unit1,但却改变了Form1中Edit的Text属性}aFuncCallBack();ModalResult:=mrOk;end;end.⾃⼰的⼀个⼩demo:第⼀个单元unit UThreadSave;interfaceuses s;type TMyfunc = procedure(readCount:Integer);stdcall; //标准调⽤,全局函数 TObjFunc = procedure(readCount:integer) of object; //对象⽅法调⽤ TThreadSave = class(TThread) private { Private declarations } { Private declarations } FreadCount:Integer; FMyfunc : TMyfunc; FObjfunc : TObjFunc; protected procedure Execute; override; public constructor create(Issuspend:boolean); destructor destroy;override; procedure SetThreadFunc(func: Pointer); procedure SetObjFunc(func: TObjFunc); property myReadCount:Integer read FreadCount write FreadCount; end;implementation{ Important: Methods and properties of objects in visual components can only be used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure Caption; begin n := 'Updated in a thread'; end;
or
Synchronize( procedure begin n := 'Updated in thread via an anonymous method' end ) ); where an anonymous method is passed. Similarly, the developer can call the Queue method with similar parameters as
above, instead passing another TThread class as the first parameter, putting the calling thread in a queue with the other thread.}{ TThreadSave }constructor (Issuspend: boolean);begin inherited create(Issuspend);end;destructor y;begin inherited;end;procedure e;begin { Place thread code here } FreeOnTerminate:=True; while not Terminated do begin if Assigned(FObjfunc) then FObjfunc(myReadCount); Sleep(100); end;end;procedure Func(func: TObjFunc);begin FObjfunc := func;end;procedure eadFunc(func: Pointer);begin FMyfunc := func;end;end.第⼆个单元unit USave2File;interfaceuses UDataStructure, UThreadSave, classes, ls, s;type TClassSave = class private FgetUnitLen:Integer; FThreadSave: TThreadSave; procedure Save2File(readCount:Integer); //对象⽅法调⽤写为对象⽅法 public constructor create; destructor destroy;override; procedure StartSave; end;//procedure Save2File(readCount:Integer);stdcall; //标准回调函数应该写为全局函数implementationuses UGlobalPara;{ TClassSave }constructor ;begin FgetUnitLen:=800; FThreadSave:=(True);// eadFunc(@Save2file); Func(Save2file);end;destructor y;begin inherited;end;//对象⽅法对应的实现函数procedure 2File(readCount:Integer);var tempstream:TMemorystream; tempLen:Integer; tempIntArr:TIntArr; tempInt:Integer; tempGetResult:Integer; I: Integer;begin tempLen:=SizeOf(Integer)*readCount; tempGetResult:=aCache(eSaveData,eIntCache,tempstream,tempLen); if tempGetResult<>0 then begin SetLength(tempIntArr,readCount); on:=0; for I := 0 to readCount do begin ffer(tempInt,SizeOf(Integer)); tempIntArr[i]:=tempInt; end; end;end;//全局回调函数对应的实现//procedure Save2File(readCount: Integer);//var// tempstream: TMemorystream;// tempLen: Integer;// tempIntArr: TIntArr;// tempInt: Integer;// tempGetResult: Integer;// I: Integer;//begin// tempLen := SizeOf(Integer) * readCount;
// tempGetResult := aCache(eSaveData, eIntCache, tempstream, tempLen);// if tempGetResult <> 0 then// begin// SetLength(tempIntArr, readCount);// on := 0;// for I := 0 to readCount do// begin// ffer(tempInt, SizeOf(Integer));// tempIntArr[I] := tempInt;// end;// end;//end;procedure ave;begin Count:=FgetUnitLen; ;end;end.测试 结果为,readCount 可以正确传递值800!(本⼈菜鸟,如有写错,敬请指正,谢谢!)
发布者:admin,转转请注明出处:http://www.yc00.com/web/1687426414a9185.html
评论列表(0条)