I am trying to learn callbacks in Delphi (7). Could not find a complete simple tutorial, so I puzzled together a few bits here and there. This is my first attempt, of course trivial.
My form contains a button and a label. For the test, I make a loop in the onClick code, and every time do a callback function.
picture of simple form with 1 button and a label
The code is below. It works, but I am in doubt if it's "correct" to have application.processmessages where I have it. And, if I define / apply the callback functionality correctly.
// ----------- demo to test Callbacks
// https://stackoverflow.com/questions/11314641/method-pointer-and-regular-procedure-incompatible
//
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TCallBackFunction = procedure(sig: integer) of object;
TForm1 = class(TForm)
lblProgress: TLabel;
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
procedure tcb (sig: integer);
public
{ Public declarations }
procedure dowithcallback(const something: integer; thefunction: TCallBackFunction);
end;
var
Form1: TForm1;
testvar : integer;
implementation
{$R *.dfm}
// test procedure used for callback argument
//
procedure TForm1.tcb(sig: integer);
begin
testvar := sig;
lblProgress.Caption := inttostr(testvar);
application.ProcessMessages ;
end;
// The procedure that defines the callback function
//
procedure TForm1.dowithcallback(
const something: integer;
thefunction: TCallBackFunction);
begin
if assigned(thefunction) then
begin
thefunction(something)
end;
end;
//
// button click
//
procedure TForm1.btn1Click(Sender: TObject);
var
i : integer;
begin
testvar := 0;
for i := 1 to 10 do
begin
dowithcallback(i, tcb);
sleep(500);
end;
end;
end.
Any feedback welcomed!
-
2\$\begingroup\$ The current question title, which states your concerns about the code, applies to too many questions on this site to be useful. The site standard is for the title to simply state the task accomplished by the code. Please see How to Ask for examples, and revise the title accordingly. \$\endgroup\$Mast– Mast ♦2022年09月27日 20:42:02 +00:00Commented Sep 27, 2022 at 20:42
1 Answer 1
This question belongs to StackOverflow but not StackExchange. The title is also misleading, as you're asking about the call to application.ProcessMessages
but not the callback function. Regarding your question, my opinion is that you should avoid putting UI code in the function and put them together with Sleep
.
The other concern is the use of testvar
. This global variable seems completely unnecessary in your code. It also makes the code thread-unsafe. Why did you use it? If you really need it, declare it as a member of TForm1
and not a global variable. It's still not thread-safe but better. Using global variables is against the principle of OOP and very bug-prone.
One last thing, as a benefit of separating codes from UI handling, both tcb
and dowithcallback
can now be declared as regular functions and not class functions. They run faster.
type
TCallBackFunction = function(sig: integer): string;
function tcb(sig: integer): string;
begin
Result := inttostr(sig);
end;
function dowithcallback(
const something: integer;
thefunction: TCallBackFunction): string;
begin
if assigned(thefunction)
then Result := thefunction(something)
// else Result := '';
// the else part is not needed because Result is defaulted to ''
end;
procedure TForm1.btn1Click(Sender: TObject);
var
i : integer;
begin
for i := 1 to 10 do
begin
lblProgress.Caption := dowithcallback(i, tcb);
application.ProcessMessages ;
sleep(500);
end;
end;