(█(█(█(█(█(█(█请教通讯和面向对象设计方面的高手--通讯如何很好的和界面分离开来!!!!!!! (100分)

  • 主题发起人 主题发起人 NetNoCenter
  • 开始时间 开始时间
TO baifeng:
呵呵,你说的这个回调的东东似乎是一个好思路,能仔细讲一下吗,WINDOWS的回调机制我不是很明白,能演示一下,就更好了!
TO 蒋劲刚:
呵呵,再找不到好的办法的话,我现在就准备考虑这个办法了,把所有的接收消息都放在一个消息池中,然后用定时器去处理!但具体处理特麻烦,不是好方法
 
我把我的意思用为代码表示出来,回调函数其实就是普通的函数,只不过是由他人调用
//通讯类:

type
TMyComm = class(COMM)
private
//接收数据
procedure RevDatas();
public
//给各FORM用的函数,用来登记要显示数据FORM的句柄、要接收那种数据、及处理数据的函数
//这就算一个回调函数,他是属于TMYCOMM,但设计的意图是给其人调用的,在这里是给那些FORM用的
function RegForm(FormHandle:THandel;RevDataStyle:integer;PProcRevDataFun:Pointer);
end;
function TMyComm.RegForm(FormHandle:THandel;RevDataStyle:integer;PProcRevDataFun:Pointer);
begin
//将这三种信息存入数组,,便于RevDatas()使用
end;

procedure TMyComm.RevDatas();
var
data:style;
begin
//分析数据,得出类型
data:=??
//根据数据类型调用FORM提供的处理函数
。。。。
end;


//其他的FORM
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
//处理数据的函数,提供给通讯类使用
function ProRevData(Datas:array of char):integer;
end;



var
Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

function TForm1.ProRevData(Datas: array of char): integer;
begin
//
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//通过调用TMYCOMM提供的函数,告诉TMYCOMM类型为1的数据,由我处理
RegForm(Handle,1,@ProRevData)
end;

end.
 
TO baifeng:
非常感谢,使用你所说的这种回调方法完全达到了我的要求,细细想来,其他诸位所说的事件也是一种回调,原理也是一样的,也可以达到这种要求,但用回调似乎更方便些!
只是有一个问题,我在
function TForm1.ProRevData(Datas: array of char): integer;
begin
//
end;

里收到数据后,假如操作TForm1里定义的私有或共有变量,如TEDIT等时,会报Delphi中常见的那种错误:
Access violation at address ......的异常,感觉是类之间互相操作时,指针操作出了问题,这个问题很棘手,不知道如何解决呢,还望继续指教,因为这种应用的目的就是希望能够实时操作界面类的东西,如果不能操作,那就没意义了

下面这段代码里我是这么写的
:.....
TYPE
TProRevData= PROCEDURE(Datas: array of char) OF OBJECT:
........
procedure TMyComm.RevDatas();
var
data:style;
p:TProRevData;
begin
//分析数据,得出类型
data:=??
//根据数据类型调用FORM提供的处理函数
//by NetNoCenter
@p:=getfuncpointerby...();//根据不同应用取得我已经注册了的ProRevData指针地址
P(data);//回调
end;

不知道这样写有没有什么问题,不过既然TForm1.ProRevData(Datas: array of char): 里已经成功收到数据,说明回调是正确的,这里感觉是不是TForm1调用了TMyComm类,然后TMyComm又来操作TForm1里的变量,造成了类的互相循环引用,所以出问题了!

 
要不你贴出你试验的原码。我这里模拟一个简单没这个问题,在D7下通过。
form1上有一个BUTTON和一个EDIT,表示你以后增的窗体,
CommUnit单元,就是你的通讯类
form2上有一个BUTTON,form2只是用来表示远程的客户端 发送数据过来

远行后,点击FORM1上的BUTTON,显示FORM2,在点FORM2的BUTTON,就模拟远程主机发送数据到通讯类,通讯类根据数据类型(协议判断),调用相应的FORM处理函数.

//项目单元
program Project2;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
CommUnit in 'CommUnit.pas',
Unit2 in 'Unit2.pas' {Form2};

{$R *.res}

begin
Application.Initialize;
aMyComm:=TMyComm.Create;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.Run;
end.

//form1
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,CommUnit, StdCtrls;

type
pProRevData=function (Datas:string):integer;


type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }

end;

//处理数据的函数,提供给通讯类使用
function ProRevData(Datas:string):integer;



var
Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

{ TForm1 }

function ProRevData(Datas: string): integer;
begin
Form1.Edit1.Text:=Datas;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
pfun:pProRevData;
begin
//通过调用TMYCOMM提供的函数,告诉TMYCOMM类型为1的数据,由我处理
pfun:=ProRevData;
aMyComm.RegForm(Handle,1,Pointer(@pfun));
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Show;
end;

end.

//CommUnit单元
unit CommUnit;

interface
type
pProRevData=function (Datas:string):integer;

type
TMyComm = class
private
pfun:Pointer;
RdataStyle:integer;
public
//接收数据
procedure RevDatas(data:string);

//给各FORM用的函数,用来登记要显示数据FORM的句柄、要接收那种数据、及处理数据的函数
//这就算一个回调函数,他是属于TMYCOMM,但设计的意图是给其人调用的,在这里是给那些FORM用的
function RegForm(FormHandle:THandle;RevDataStyle:integer;PProcRevDataFun:Pointer):integer;
end;
var
aMyComm:TMyComm;

implementation

uses SysUtils;

{ TMyComm }

function TMyComm.RegForm(FormHandle: THandle; RevDataStyle: integer;
PProcRevDataFun: Pointer): integer;
begin
//
RdataStyle:=RevDataStyle;
pfun:=PProcRevDataFun;

end;

procedure TMyComm.RevDatas(data:string);
var
style:integer;
profun:pProRevData;
begin
style:=StrToInt(copy(data,1,1));
if style=RdataStyle then
begin
profun:=pProRevData(pfun);
profun(data);
end;
end;

end.

//form2
unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

uses CommUnit;

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
aMyComm.RevDatas('1aaab');
end;

end.



 
前面那个问题解决了,是我指针操作错误的问题,谢谢,可是现在有个问题:
这是在你代码基础上改了一下的:

//==================项目文件,没做任何改动========================
program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas';

{$R *.res}

begin
Application.Initialize;
aMyComm:=TMyComm.Create;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

//====================单元一======================
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,Unit2, StdCtrls,Unit3;

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
function ProRevData(Datas: string): integer;//这里我把这个全局函数提到界面类里来了
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
with TFORM2.Create(NIL) DO
TRY
SHOWMODAL;
FINALLY
FREE;
END;
end;
function TForm1.ProRevData(Datas: string): integer;
begin
form1.Edit1.Text:=Datas;//?????????问题在这里,这里假如现在这样就没有任何问题,但为什么一定要加一个
//FORM1呢,Edit1.Text:=Datas; 这样就不行????????????
end;
procedure TForm1.FormCreate(Sender: TObject);
var
pfun:pProRevData;
begin
//通过调用TMYCOMM提供的函数,告诉TMYCOMM类型为1的数据,由我处理
pfun:=ProRevData;
aMyComm.RegForm(Handle,1,Pointer(@pfun));
end;

end.
//=================//没做任何改动===================
unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,Unit3, StdCtrls;

type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
aMyComm.RevDatas('1aaab');
end;

end.
//===================//=======================
unit Unit3;
//CommUnit单元

interface
type
pProRevData=function (Datas:string): integer of object;//定义为对象函数,便于在类里使用

type
TMyComm = class
private
pfun:Pointer;
RdataStyle:integer;
public
//接收数据
procedure RevDatas(data:string);

//给各FORM用的函数,用来登记要显示数据FORM的句柄、要接收那种数据、及处理数据的函数
//这就算一个回调函数,他是属于TMYCOMM,但设计的意图是给其人调用的,在这里是给那些FORM用的
function RegForm(FormHandle:THandle;RevDataStyle:integer;PProcRevDataFun:Pointer):integer;
end;
var
aMyComm:TMyComm;

implementation

uses SysUtils;

{ TMyComm }

function TMyComm.RegForm(FormHandle: THandle; RevDataStyle: integer;
PProcRevDataFun: Pointer): integer;
begin
//
RdataStyle:=RevDataStyle;
pfun:=PProcRevDataFun;

end;

procedure TMyComm.RevDatas(data:string);
var
style:integer;
profun:pProRevData;
begin
style:=StrToInt(copy(data,1,1));
if style=RdataStyle then
begin
@profun:=pfun;
profun(data);
end;
end;

end.
 
我把接受函数
function ProRevData(Datas: string): integer;//
提到类里是有意义的,这样
function TForm1.ProRevData(Datas: string): integer;
begin
form1.Edit1.Text:=Datas;//?????????问题在这里,这里假如现在这样就没有任何问题,但为什么一定要加一个FORM1呢,Edit1.Text:=Datas; 这样就不行????????????
end;
里的form1.Edit1.Text:=Datas;就可以改为Edit1.Text:=Datas;,这样在我动态创建多个TFORM1的情况下,就不会和固定的TFORM1相关了,否则这里直接指定为form1,则在有多个同类窗体的情况下,就很难去调度了。。。
 
问题圆满解决,接分。。。
 
to netnocenter;我的意思是这样:每个socket(不过是server的还是client的)收到信息后需要向不同的窗口发送信息。在每隔窗体中都要有一个接收信息的东西吧,假设是memo1.那完全可以这样,在通讯层单元文件中定义函数:
function SQUAllRead_Connect(ReadSock: TCustomWinSocket;
SQUAll_Head: tSQUAll_HEAD_tag;//自定义数据体的数据头,包含该数据体的属性
fmmemo:Tmemo //这个memo存放发给它的信息。
):LongWord;
服务端serversocket1.onread事件
procedure TFm_ServerMain.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
...
SQUAllRead_Connect(Socket,SQUAll_HEAD_tag,from1.memo);//把收到的信息交给这个函数处理,把信息发给form1的memo1.
...
end;
 
后退
顶部