DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: g929959149
今日帖子: 25
在线用户: 8
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/27 19:06:08
标题:
为TAnimation增加回调支持 浏览:558
加入我的收藏
楼主: TAnimation有一个动画结束事件,当动画完成后触发这个事件,但是没有提供回调支持,就是在Start一个动画时,就指定动画完成后调用的方法,以取代OnFinish事件。查看QC,有人早在10.2.3就提到了这个需求:

 https://quality.embarcadero.com/browse/RSP-20802

遗憾的是,直到现在的Delphi 11.1版本也没有实现,也许是官方觉得不重要吧,不得矣,自己加了一下。

如果你有QC账号,一起去投个票,督促官方解决。

//为TAnimation重载一个Start方法:

//++++++++++ by 红鱼儿
procedure Start(AFinishCallback:TFinishCallback);overload;
//++++++++++ by 红鱼儿
代码实现:

//++++++++++ by 红鱼儿
procedure TAnimation.Start(AFinishCallback: TFinishCallback);
begin
  FFinishCallback:=AFinishCallback;
  Start;
end;
//++++++++++ by 红鱼儿

再修改DoFinish方法:

procedure TAnimation.DoFinish;
begin
 //++++++++++ by 红鱼儿
  if Assigned(FFinishCallback) then
     FFinishCallback(Self)
  else
 //++++++++++ by 红鱼儿
  if Assigned(FOnFinish) then
    FOnFinish(Self);
end;

OK,现在调用一下:

procedure TCameraForm.PlayFormAnimationOut;
var
  fa: TFloatAnimation;
begin
  fa := Self.FindComponent('FloatAnimation2_') as TFloatAnimation;
  if fa <> nil then
  begin
    fa.Start(procedure(Sender:TObject)//使用回调函数来处理动画完成后的动作
          begin
          Close;
          end);
  end
end;

上面这段代码,fa.Start启动动画时就指定了完成需要执行的动作,这样,我就不用去用事件来处理了。

万事大吉!

需要代码的同学可以联系我,免得自己再改了。
----------------------------------------------
-我的博客
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/4/27 21:07:07
1楼: hi @bdl1

Why didn't Embarcadero implement something like this?

Perhaps for the simple fact that an animation is of a single character and should not interfere with the flow of the animated component.

In this way, using a "callback" function or whatever name you want to give it can, and shouldn't, interfere with the natural flow of the animation.

Or in the most extreme case, maybe even break it.

So, in critical situations, it's best to let things flow naturally... otherwise "things" can turn against you.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/28 21:40:18
2楼: 感谢回复。

我没有象你说的,破坏动画的运行,我只是想在动画结束后执行我的方法,这样来取代onFinish事件。
----------------------------------------------
-我的博客
作者:
男 supermay (supermay) ★☆☆☆☆ -
盒子活跃会员
2022/4/29 9:45:51
3楼: 有OnFinish事件了,为什么加要加一个完成后回调?OnFinish事件不就是回调了吗?
----------------------------------------------
https://shop66090024.taobao.com/?spm=a313o.7775905.1998679131.d0011.6f6f2796Z7e3JX
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/4/29 10:33:11
4楼: 有点没看懂楼主的意思。

那个 OnFinish 事件,就是播放完成后的回调啊。

什么是事件?本质上就是让你做一个你自己的方法,把这个方法的指针放进去让它调用,就是个回调。

从实现功能上来说,既然已经有了 OnFinish 事件,你在里面写代码就好了。或者,你自己写一个方法,只要参数格式和 OnFinish 一样,就可以把它指定给 OnFinish 事件,也就是把你写的方法的指针,赋予给这个控件,这个控件在需要回调的时候就调用了你的方法。

我拿最常用的 Button1.OnClick 举例:

1. 设计期,双击 Edit1,IDE 自动产生 OnClick 的代码框架,我填入代码,如下:
procedure TForm1.Edit1Click(Sender: TObject);
begin
  Edit1.Text := 'OnClick';
end;

如果运行,我鼠标点它一下,它就显示 OnClick;

2. 我自己写一个私有的方法,其实公有也没问题,如下:
procedure TForm1.DoMyOnClick(Sender: TObject);
begin
  Edit1.Text := 'DoMyOnClick';
end;

3. 增加一个 CheckBox1,代码如下:
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.IsChecked then
  begin
    Edit1.OnClick := Self.Edit1Click;
  end
  else
  begin
    Edit1.OnClick := Self.DoMyOnClick;
  end;
end;

这个 CheckBox1 勾选时,鼠标点 Edit1,和不勾选时,鼠标点 Edit1 执行的就是不同的方法。

这个 CheckBox1 的代码,说明的就是你如何将你自己的方法,作为一个回调函数,赋予 Edit1 这个控件,让它回调。

重复一遍,所谓的事件,本质就是一个回调函数的指针。你可以给这个事件,指定任意的函数,作为让它回调的函数。只是需要注意,回调函数,一定要符合它要求的参数结构。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/4/29 10:42:11
5楼: 用 Delphi 的 IDE,双击一个控件,或者在属性面板的事件页里面选择一个事件双击,Delphi 就自动产生事件的代码框架,并且代码里面看不到把这个事件方法赋予事件的代码,因此,初学的就容易被误导,以为事件就是那个固定的 OnClick。

其实这个 IDE 自动创建的事件方法的代码框架方法,是有把它的指针赋予给事件的,只是那个赋值的代码不是 PASCAL 代码,是在 Form 的描述里面。

比如我上面那个例子,设计期,鼠标右键点 Form1,选择菜单里面的:View as Text,就会看到这个 Form 的描述代码,里面关于 Edit1 的部分如下:


  object Edit1: TEdit
    Touch.InteractiveGestures = [LongTap, DoubleTap]
    TabOrder = 10
    Position.X = 440.0000000000
    Position.Y = 112.0000000000
    OnKeyDown = Edit1KeyDown
    OnKeyUp = Edit1KeyUp
    OnClick = Edit1Click
  end

注意上面代码里面的 OnClick = Edit1Click 这行。
----------------------------------------------
-
作者:
男 wk_knife (wk_knife) ★☆☆☆☆ -
盒子活跃会员
2022/4/29 10:49:10
6楼: 楼主也许要自己继承扩展下TAnimation控件吧。
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/4/29 10:56:56
6楼: 同疑问:OnFinish事件不就是回调了吗?
----------------------------------------------
Bye bye DDRFAN...
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 11:59:35
7楼: 在一个独立的unit中,我想单独写一个公共函数,这时候无法写成这样:
FloatAnimation2.OnFinish:=procedure (Sender:TObject)
begin
....
end;

我所有的Fotm单元,都调用这个函数。
所以我需要回调支持,而不是这个onFinish事件。
----------------------------------------------
-我的博客
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 12:01:17
8楼: procedure PlayFormAnimationOut(AOwner:TForm);
var
  fa: TFloatAnimation;
begin
  fa := AOwner.FindComponent('FloatAnimation2_') as TFloatAnimation;
  if fa <> nil then
  begin
    fa.Start(procedure(Sender:TObject)
          begin
          AOwner.Close;
          end);
  end
end;
//这是我的函数,用回调可以实现。而用事件则不行。
----------------------------------------------
-我的博客
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 12:04:15
9楼: 其实,我想写两个函数,对应窗口打开与关闭,都播入动画,在关闭时,等动画完成后,关闭窗口。
这两个函数放到独立的单元中,与form单元分开。
----------------------------------------------
-我的博客
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 12:05:11
10楼: PlayFormAnimationOut是关闭窗口时,播放动画。
----------------------------------------------
-我的博客
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/4/29 13:20:21
11楼: try this:

----------
interface

  FMX.Ani;

type
  TFloatAnimation = class(FMX.Ani.TFloatAnimation)
  protected
    procedure DoFinish; override;  // <------
  end;
  { TFloatAnimation }

  { TFloatAnimation }

....
implementation

procedure TFloatAnimation.DoFinish;
begin
  inherited ;
  //
  // what you need ?
  ShowMessage('dont use "dialog" on animation... >:) ');
end;

procedure TForm1.FloatAnimation1Finish(Sender: TObject);
begin
  ShowMessage('hello');
end;

----------
then, the all "TFloatAnimation" in your project will use it!

good luck
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 13:25:31
12楼: 这个方法好,我试试,先感谢!
----------------------------------------------
-我的博客
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/4/29 13:29:09
13楼: fixed!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/4/29 13:31:58
14楼: screenshot
此帖子包含附件:
PNG 图像
大小:31.9K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/4/29 13:45:23
15楼: 代码放在哪个单元,这个本身不是问题啊。

什么是回调?一个事件,其本质就是回调。

你的代码放在哪个单元,都可以用事件来执行它。
----------------------------------------------
-
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 13:53:43
13楼:   TFloatAnimation = class(FMX.Ani.TFloatAnimation)
  private type
    TFinishCallback = TProc<TObject>;
  private
    FFinishCallback:TFinishCallback;
  protected
    procedure DoFinish; override;
  public
    procedure Start(FinishCallback:TFinishCallback=nil);reintroduce;
  end;

{ TFloatAnimation }

procedure TFloatAnimation.DoFinish;
begin
  inherited;

  if Assigned(FFinishCallback) then
     FFinishCallback(Self);

end;

procedure TFloatAnimation.Start(FinishCallback: TFinishCallback);
begin

  FFinishCallback:=FinishCallback;
  inherited Start;

end;

测试通过,达到目的。
再一次感谢emailx45!
----------------------------------------------
-我的博客
作者:
男 bdl1 (bdl1) ▲▲▲▲△ -
注册会员
2022/4/29 13:54:21
16楼: 现在,我不用直接改源码了!
----------------------------------------------
-我的博客
作者:
男 supermay (supermay) ★☆☆☆☆ -
盒子活跃会员
2022/4/29 14:03:08
17楼: 继承是一个很好玩的。不要什么都想着改原来的源码
----------------------------------------------
https://shop66090024.taobao.com/?spm=a313o.7775905.1998679131.d0011.6f6f2796Z7e3JX
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/4/29 16:15:27
18楼: 13 楼的做法,基本上算是最佳实践,标准操作了。
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2022/4/29 23:33:55
19楼: 我猜楼主的意思应该是因为onfinish事件必须是一个对象方法(procedure of object)

而楼主的代码在一个独立单元里, 所以是个普通方法, 那么回调也就自然是需要一个普通方法或者一个匿名方法
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/4/30 11:32:33
20楼: 在一个独立单元里面,也可以自己定义一个类,把方法写里面,那就是对象方法了嘛。

所以这个理论上不是独立单元的问题。

即便不是独立单元,也可以自己定义一个普通方法。

如果按照传统的回调函数或者 C 语言的回调函数来说,回调函数应该是一个【普通方法】;但是,从回调的本质来说,即便是对象方法,它也是采用【指针】的方式把方法填入需要被回调的地方,在适当的时候被调用。只不过对象方法的【指针】不是传统的那种指针。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v2.1 版权所有 页面执行23.4375毫秒 RSS