全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:6253
推到 Plurk!
推到 Facebook!

請教一下有關callback function的用法(與event的不同)?

答題得分者是:jow
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-12-23 18:08:16 IP:219.87.xxx.xxx 訂閱
請問一下,有關於我的問題描述一下,我有看過vc寫的event方式,是被觸發後才會被執行,然後我需要在delphi上做這種方式的實現,然後上網查了一下callback function,大多數人的說明都是說要被執行時才會被call到,而不用像使用像是while(反正就是程式卡在那邊等的意思,thread好像也是在那等哦)的方式一直等,這樣cpu好像會被吃掉資源一樣,而像vc上使用event的方式,好像沒什麼佔cpu,並且只會在被觸發時才會被執行,這樣與我查的callback function說明很相似,但是問題來了,為什麼很多人解釋callback function都是指傳入function pointer的方式在解釋,因為我需要是像有一個長駐在系統上的一個程式(有點像是activex或是像service這種東西,如果觀念不對請糾正,謝謝),然後我的程式(指ap端)會做我正常軟體要執行的程式,但是一旦有事件(我不知這樣叫對不對)被觸發後,會有訊息告知我的ap程式,然後ap才會去處理這個事件,不然就不管這個事件(指不用一直去等),請問這樣子方式可以利用什麼方法實現呢,目前到在google中,但沒有一個局體的方向,請各位有這方面的知識,可以教導一下,謝謝你的收看。
------
DELPHI初學者
DelphiJob
一般會員


發表:1
回覆:4
積分:6
註冊:2009-12-22

發送簡訊給我
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-12-23 23:24:50 IP:59.115.xxx.xxx 訂閱
你問的是很深的根基問題,很深喔! 許多人不了解很深也是可以寫程式的,但就是無法寫到純青。

我認為,相信應該沒錯, event 與 callback 其實是很"等值"的東西或"說詞"或"技術"

windows 被稱叫 event drive 的作業系統 ,event drive 就是指由事件來驅動程式被執行。 event 這個詞是用來說明,「當程式收到某訊息後才被執行」。而callback這個詞則是「實現事件驅動程式的方法」。 event 是一種概念,一種結構。而callback就是為了達成這樣結構的實作方式。

你必須先了解winodws是如何把鍵盤,mouse等訊息queue住,然後windows"主動"去執行對應的程式。簡單的講是應用程式一開始會向系統註冊一些資訊,其中就含有一個function pointer (叫 windproc)… 當使用者在該應用程式上做了一些輸入時,先產生訊息的結構送到系統,系統比對後知道是某註冊過的程式,於是例用當時告知的function pointer來 主動的呼叫該程式。

mouse等行為就產生了event,而有了這個event後就例用callback的方式來呼叫。

再深入下去有更多的東西要說,都和作業系統有關…一時半刻也無從講。你就朝這方向去查或去想吧!


註: 你說的vc的event寫法其實和delphi/bcb裡把某button按二下,然後開始寫其中的程式碼是一樣的。只是vc的寫法很接近windows api的層級,你要了解ui上的button等id與資源,然後自己把message"接入"自己的程式(使用macro)。但這些東西delphi/bcb通通幫你做掉了,所以你沒感覺,所以你很方便,所以…許多人因此無法真的了解底層,因為不了解也可以按二下就寫 ^_^ 。
good luck!
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2009-12-23 23:31:15, 註解 無‧
DelphiJob
一般會員


發表:1
回覆:4
積分:6
註冊:2009-12-22

發送簡訊給我
#4 引用回覆 回覆 發表時間:2009-12-23 23:53:54 IP:112.104.xxx.xxx 訂閱

Event drive 說詞 若使用 Message drive 會更貼切嗎?
因Win32 SDK 並無Event 這個東西嗎? MFC 才出現嗎?



===================引 用 aftcast 文 章===================
你問的是很深的根基問題,很深喔! 許多人不了解很深也是可以寫程式的,但就是無法寫到純青。

我認為,相信應該沒錯, event 與 callback 其實是很"等值"的東西或"說詞"或"技術"

windows 被稱叫 event drive 的作業系統 ,event drive 就是指由事件來驅動程式被執行。 event 這個詞是用來說明,「當程式收到某訊息後才被執行」。而callback這個詞則是「實現事件驅動程式的方法」。 event 是一種概念,一種結構。而callback就是為了達成這樣結構的實作方式。

你必須先了解winodws是如何把鍵盤,mouse等訊息queue住,然後windows"主動"去執行對應的程式。簡單的講是應用程式一開始會向系統註冊一些資訊,其中就含有一個function pointer (叫 windproc)… 當使用者在該應用程式上做了一些輸入時,先產生訊息的結構送到系統,系統比對後知道是某註冊過的程式,於是例用當時告知的function pointer來 主動的呼叫該程式。

mouse等行為就產生了event,而有了這個event後就例用callback的方式來呼叫。

再深入下去有更多的東西要說,都和作業系統有關…一時半刻也無從講。你就朝這方向去查或去想吧!


註: 你說的vc的event寫法其實和delphi/bcb裡把某button按二下,然後開始寫其中的程式碼是一樣的。只是vc的寫法很接近windows api的層級,你要了解ui上的button等id與資源,然後自己把message"接入"自己的程式(使用macro)。但這些東西delphi/bcb通通幫你做掉了,所以你沒感覺,所以你很方便,所以…許多人因此無法真的了解底層,因為不了解也可以按二下就寫 ^_^ 。
good luck!
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2009-12-24 00:25:12 IP:59.115.xxx.xxx 訂閱
嗯,認同delphijob說的詞句。 Message Drive 應該是更多人使用的詞!  但概念上講的是同一回事。 win32 sdk 上的確是沒用到event,而用message…

但這二詞有那麼一點互用,比如說:

message handler 訊息處理的函式。
event handler 事件處理函式。

這種情形下,event的用法就比較多。

總之,概念吧,概念的理解比用詞重要些。謝謝 delphijob 的提供 ^_^

此外,覺得event 的用詞比message的用詞來的更 "高階" 或說更"抽象"一點的概念用語。message比較具體點。
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2009-12-24 11:32:24 IP:203.70.xxx.xxx 未訂閱
以下程式提供你參考
希望有幫助...

[code delphi]
unit fMain;

interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls;

const
//User-Define Windows Message
WM_GEN_RANDOM = WM_USER 10000;

type
//User-Define Windows Message Record
TWMGenRandom = record
Msg: Cardinal;
Counter: Integer;
RndNumber: Integer;
Result: Longint;
end;

//User-Define Callback Function
TMyGetFontColor = function: TColor of object;

//User-Define Enevt Type
TMyOnGetSeedEvent = procedure(Sender: TObject; var Seed: Integer) of object;

{ TMyWinControl }
//User-Define TWinControl (with Window Handle)
TMyWinControl = class(TCustomControl)
private
FCounter: Integer;
FRndNumber: Integer;
function GET_FONT_COLOR: TColor;//CALLBACK FUNCTION
procedure WMGenRandom(var Message: TWMGenRandom); message WM_GEN_RANDOM;
public
procedure Paint; override;
end;

{ TMyGraphicControl }
//User-Define TGraphicControl (without Window Handle)
TMyGraphicControl = class(TGraphicControl)
private
FCounter: Integer;
FRndNumber: Integer;
function GET_FONT_COLOR: TColor;//CALLBACK FUNCTION
//TGraphicControl cannot receive any Message...
procedure WMGenRandom(var Message: TWMGenRandom); message WM_GEN_RANDOM;
public
procedure Paint; override;
end;

TfrmMain = class;

{ TMyEventThread }
//Random Number Generator...
TMyEventThread = class(TThread)
private
FCounter: Integer;
FOnGetSeed: TMyOnGetSeedEvent;
FOwner: TfrmMain;
FRndNumber: Integer;
FSeed: Integer;
protected
procedure Execute; override;
public
constructor Create(AOwner: TfrmMain); reintroduce;
property OnGetSeed: TMyOnGetSeedEvent read FOnGetSeed write FOnGetSeed;
end;

{ TfrmMain }
TfrmMain = class(TForm)
CheckBox1: TCheckBox;
procedure CheckBox1Click(Sender: TObject);
private
FMyEventThread: TMyEventThread;
procedure DO_OnGetSeed(Sender: TObject; var Seed: Integer);
procedure WMGenRandom(var Message: TWMGenRandom); message WM_GEN_RANDOM;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;

//public function with Callback
procedure PaintTest(Canvas: TCanvas; ClientRect: TRect;
ClassName: string; GetFontColor: TMyGetFontColor; Counter, RndNumber: Integer);

var
frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure PaintTest(Canvas: TCanvas; ClientRect: TRect; ClassName: string;
GetFontColor: TMyGetFontColor; Counter, RndNumber: Integer);
begin
Canvas.Brush.Color := clBlack;
Canvas.Brush.Style := bsSolid;
Canvas.FillRect(ClientRect);
Canvas.Font.Name := 'Arial';
Canvas.Font.Height := 24;
Canvas.Font.Color := GetFontColor;
Canvas.TextOut(5,00,ClassName);
Canvas.Font.Color := GetFontColor;
Canvas.TextOut(5,25,'Counter = ' IntToStr(Counter));
Canvas.Font.Color := GetFontColor;
Canvas.TextOut(5,50,'RanNumber = ' IntToStr(RndNumber));
end;

{ TMyWinControl }
function TMyWinControl.GET_FONT_COLOR: TColor;
begin
Result := RGB(Random($100),Random($100),Random($100));
end;

procedure TMyWinControl.Paint;
begin
PaintTest(Canvas,ClientRect,ClassName,GET_FONT_COLOR,FCounter,FRndNumber);
end;

procedure TMyWinControl.WMGenRandom(var Message: TWMGenRandom);
begin
FCounter := Message.Counter;
FRndNumber := Message.RndNumber;
Invalidate;
end;

{ TMyGraphicControl }

function TMyGraphicControl.GET_FONT_COLOR: TColor;
begin
case (FRndNumber div 10) mod 3 of
0: Result := clYellow;
1: Result := clRed;
else Result := clWhite;
end;
end;

procedure TMyGraphicControl.Paint;
begin
PaintTest(Canvas,ClientRect,ClassName,GET_FONT_COLOR,FCounter,FRndNumber);
end;

procedure TMyGraphicControl.WMGenRandom(var Message: TWMGenRandom);
begin
FCounter := Message.Counter;
FRndNumber := Message.RndNumber;
Invalidate;
end;

{ TMyEventThread }

constructor TMyEventThread.Create(AOwner: TfrmMain);
begin
inherited Create(True);
FOwner := AOwner;
FreeOnTerminate := True;
Resume;
end;

procedure TMyEventThread.Execute;
var
Delay: Cardinal;
begin
FCounter := 0;
while not Terminated do
begin
Delay := GetTickCount 100;
Inc(FCounter);
if Assigned(FOnGetSeed)
then FOnGetSeed(Self,FSeed)
else FSeed := 10;
FRndNumber := Random(FSeed);
PostMessage(FOwner.Handle,WM_GEN_RANDOM,FCounter,FRndNumber);
while GetTickCount < Delay do Application.ProcessMessages;
end;
end;

{ TfrmMain }

constructor TfrmMain.Create(AOwner: TComponent);
begin
inherited;

CheckBox1.BoundsRect := Rect(0,0,100,20);

with TMyWinControl.Create(Self) do
begin
Parent := Self;
BoundsRect := Rect(10,25,300,100);
end;

with TMyGraphicControl.Create(Self) do
begin
Parent := Self;
BoundsRect := Rect(10,135,300,210);
end;

FMyEventThread := TMyEventThread.Create(Self);

Width := 350;
Height := 300;

end;

destructor TfrmMain.Destroy;
begin
FMyEventThread.Terminate;
inherited;
end;

procedure TfrmMain.DO_OnGetSeed(Sender: TObject; var Seed: Integer);
begin
Seed := Random( MaxInt);
end;

procedure TfrmMain.WMGenRandom(var Message: TWMGenRandom);
var
I: Integer;
begin
for I := 0 to ComponentCount-1 do
begin
if Components[I] is TWinControl then
begin
//Owner post received message to owned TWinControls
PostMessage(
TWinControl(Components[I]).Handle,
Message.Msg,
Message.Counter,
Message.RndNumber);
end
else if Components[I] is TMyGraphicControl then
begin
//Owner call to owned TMyGraphicControl's function
TMyGraphicControl(Components[I]).WMGenRandom(Message);
end;
end;
end;

procedure TfrmMain.CheckBox1Click(Sender: TObject);
begin
//Dynamic hooking event handler...
if Assigned(FMyEventThread) then
begin
if CheckBox1.Checked
then FMyEventThread.OnGetSeed := DO_OnGetSeed
else FMyEventThread.OnGetSeed := nil;
end;
end;

end.
[/code]

謹供參考...

macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#7 引用回覆 回覆 發表時間:2009-12-29 17:17:17 IP:219.87.xxx.xxx 訂閱
真奇怪,總算可以回覆了,先試試一下,有關念上問題再來請教大大,謝謝。


===================引 用 jow 文 章===================
以下程式提供你參考
希望有幫助...

[code delphi]
unit fMain;

interface
uses
? Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls;

const
? //User-Define Windows Message
? WM_GEN_RANDOM = WM_USER 10000;

type
? //User-Define Windows Message Record
? TWMGenRandom = record
??? Msg: Cardinal;
??? Counter: Integer;
??? RndNumber: Integer;
??? Result: Longint;
? end;

? //User-Define Callback Function
? TMyGetFontColor = function: TColor of object;
?
? //User-Define Enevt Type
? TMyOnGetSeedEvent = procedure(Sender: TObject; var Seed: Integer) of object;

{ TMyWinControl }
? //User-Define TWinControl (with Window Handle)
? TMyWinControl = class(TCustomControl)
? private
??? FCounter: Integer;
??? FRndNumber: Integer;
??? function GET_FONT_COLOR: TColor;//CALLBACK FUNCTION
??? procedure WMGenRandom(var Message: TWMGenRandom); message WM_GEN_RANDOM;
? public
??? procedure Paint; override;
? end;

{ TMyGraphicControl }
? //User-Define TGraphicControl (without Window Handle)
? TMyGraphicControl = class(TGraphicControl)
? private
??? FCounter: Integer;
??? FRndNumber: Integer;
??? function GET_FONT_COLOR: TColor;//CALLBACK FUNCTION
??? //TGraphicControl cannot receive any Message...
??? procedure WMGenRandom(var Message: TWMGenRandom); message WM_GEN_RANDOM;
? public
??? procedure Paint; override;
? end;

? TfrmMain = class;

{ TMyEventThread }
? //Random Number Generator...
? TMyEventThread = class(TThread)
? private
??? FCounter: Integer;
??? FOnGetSeed: TMyOnGetSeedEvent;
??? FOwner: TfrmMain;
??? FRndNumber: Integer;
??? FSeed: Integer;
? protected
??? procedure Execute; override;
? public
??? constructor Create(AOwner: TfrmMain); reintroduce;
??? property OnGetSeed: TMyOnGetSeedEvent read FOnGetSeed write FOnGetSeed;
? end;

{ TfrmMain }
? TfrmMain = class(TForm)
??? CheckBox1: TCheckBox;
??? procedure CheckBox1Click(Sender: TObject);
? private
??? FMyEventThread: TMyEventThread;
??? procedure DO_OnGetSeed(Sender: TObject; var Seed: Integer);
??? procedure WMGenRandom(var Message: TWMGenRandom); message WM_GEN_RANDOM;
? public
??? constructor Create(AOwner: TComponent); override;
??? destructor Destroy; override;
? end;

? //public function with Callback
? procedure PaintTest(Canvas: TCanvas; ClientRect: TRect;
??? ClassName: string; GetFontColor: TMyGetFontColor; Counter, RndNumber: Integer);

var
? frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure PaintTest(Canvas: TCanvas; ClientRect: TRect; ClassName: string;
? GetFontColor: TMyGetFontColor; Counter, RndNumber: Integer);
begin
? Canvas.Brush.Color := clBlack;
? Canvas.Brush.Style := bsSolid;
? Canvas.FillRect(ClientRect);
? Canvas.Font.Name := 'Arial';
? Canvas.Font.Height := 24;
? Canvas.Font.Color := GetFontColor;
? Canvas.TextOut(5,00,ClassName);
? Canvas.Font.Color := GetFontColor;
? Canvas.TextOut(5,25,'Counter = ' IntToStr(Counter));
? Canvas.Font.Color := GetFontColor;
? Canvas.TextOut(5,50,'RanNumber = ' IntToStr(RndNumber));
end;

{ TMyWinControl }
function TMyWinControl.GET_FONT_COLOR: TColor;
begin
? Result := RGB(Random($100),Random($100),Random($100));
end;

procedure TMyWinControl.Paint;
begin
? PaintTest(Canvas,ClientRect,ClassName,GET_FONT_COLOR,FCounter,FRndNumber);
end;

procedure TMyWinControl.WMGenRandom(var Message: TWMGenRandom);
begin
? FCounter := Message.Counter;
? FRndNumber := Message.RndNumber;
? Invalidate;
end;

{ TMyGraphicControl }

function TMyGraphicControl.GET_FONT_COLOR: TColor;
begin
? case (FRndNumber div 10) mod 3 of
??? 0: Result := clYellow;
??? 1: Result := clRed;
??? else Result := clWhite;
? end;
end;

procedure TMyGraphicControl.Paint;
begin
? PaintTest(Canvas,ClientRect,ClassName,GET_FONT_COLOR,FCounter,FRndNumber);
end;

procedure TMyGraphicControl.WMGenRandom(var Message: TWMGenRandom);
begin
? FCounter := Message.Counter;
? FRndNumber := Message.RndNumber;
? Invalidate;
end;

{ TMyEventThread }

constructor TMyEventThread.Create(AOwner: TfrmMain);
begin
? inherited Create(True);
? FOwner := AOwner;
? FreeOnTerminate := True;
? Resume;
end;

procedure TMyEventThread.Execute;
var
? Delay: Cardinal;
begin
? FCounter := 0;
? while not Terminated do
? begin
??? Delay := GetTickCount 100;
??? Inc(FCounter);
??? if Assigned(FOnGetSeed)
??? then FOnGetSeed(Self,FSeed)
??? else FSeed := 10;
??? FRndNumber := Random(FSeed);
??? PostMessage(FOwner.Handle,WM_GEN_RANDOM,FCounter,FRndNumber);
??? while GetTickCount < Delay do Application.ProcessMessages;
? end;
end;

{ TfrmMain }

constructor TfrmMain.Create(AOwner: TComponent);
begin
? inherited;
?
? CheckBox1.BoundsRect := Rect(0,0,100,20);

? with TMyWinControl.Create(Self) do
? begin
??? Parent := Self;
??? BoundsRect := Rect(10,25,300,100);
? end;

? with TMyGraphicControl.Create(Self) do
? begin
??? Parent := Self;
??? BoundsRect := Rect(10,135,300,210);
? end;

? FMyEventThread := TMyEventThread.Create(Self);

? Width := 350;
? Height := 300;
?
end;

destructor TfrmMain.Destroy;
begin
? FMyEventThread.Terminate;
? inherited;
end;

procedure TfrmMain.DO_OnGetSeed(Sender: TObject; var Seed: Integer);
begin
? Seed := Random( MaxInt);
end;

procedure TfrmMain.WMGenRandom(var Message: TWMGenRandom);
var
? I: Integer;
begin
? for I := 0 to ComponentCount-1 do
? begin
??? if Components[I] is TWinControl then
??? begin
? //Owner post received message to owned TWinControls
? PostMessage(
??? TWinControl(Components[I]).Handle,
??? Message.Msg,
??? Message.Counter,
??? Message.RndNumber);
??? end
??? else if Components[I] is TMyGraphicControl then
??? begin
? //Owner call to owned TMyGraphicControl's function
? TMyGraphicControl(Components[I]).WMGenRandom(Message);
??? end;
? end;
end;

procedure TfrmMain.CheckBox1Click(Sender: TObject);
begin
? //Dynamic hooking event handler...
? if Assigned(FMyEventThread) then
? begin
??? if CheckBox1.Checked
??? then FMyEventThread.OnGetSeed := DO_OnGetSeed
??? else FMyEventThread.OnGetSeed := nil;
? end;
end;

end.
[/code]

謹供參考...
?
------
DELPHI初學者
系統時間:2024-04-26 20:11:26
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!