我一直在努力争取一两天,无法在任何地方找到答案。我想this answer might help但事实并非如此。
在我的示例代码中,我有两个 Timage 组件,每个组件都包含一个“开始图像”。单击“开始按钮”时,会创建两个匿名线程,一个在“开始图像”和“结束图像”之间激活Image1,另一个对 Image2 执行相同操作。
我的问题是,当 KillAnimation 布尔值设置为True时,两个动画应该停止(他们这样做),但只有一个线程退出,另一个停止动画但是让图像保持在动画。
如果我也使用预定义的线程,我也会遇到同样的问题。
示例应用程序只有两个图像,真实世界的应用程序可以有15到24之间的任何地方。匿名线程似乎适合,因为我可以创建它们,而不必担心定义多达24个TThreads。我希望这是有道理的。
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Objects,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.Ani, FMX.Effects,
FMX.Filter.Effects;
type
TForm1 = class(TForm)
Image1: TImage;
Image2: TImage;
BtnStop: TButton;
BtnStart: TButton;
BtnReset: TButton;
procedure BtnStopClick(Sender: TObject);
procedure BtnStartClick(Sender: TObject);
procedure BtnResetClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure createthread(TheImage: TImage; TargetBMP: String);
end;
var
Form1: TForm1;
KillAnimation: Boolean;
implementation
{$R *.fmx}
procedure TForm1.BtnStopClick(Sender: TObject);
begin
KillAnimation := true;
end;
procedure TForm1.createthread(TheImage: TImage; TargetBMP: String);
begin
{ The thread works right up until it is stopped. Even though two
threads are started only one finishes. In addition, the images
do not end up as the target image, and neither image can be
reset even if I reload them from files. }
TThread.CreateAnonymousThread(
procedure()
var
Wiggle: TWiggleTransitionEffect;
TheFloat: TFloatAnimation;
begin
TThread.NameThreadForDebugging('Animate ' + TheImage.Name);
Wiggle := TWiggleTransitionEffect.Create(Nil);
Wiggle.RandomSeed := 0.3;
Wiggle.Progress := 0;
Wiggle.Parent := TheImage;
TThread.Synchronize(TThread.CurrentThread,
procedure()
Begin
Wiggle.Target.LoadFromFile(TargetBMP)
end);
TheFloat := TFloatAnimation.Create(Nil);
TheFloat.Parent := Wiggle;
TheFloat.PropertyName := 'Progress';
TheFloat.Duration := 2;
TheFloat.AutoReverse := true;
TheFloat.Loop := true;
TheFloat.StartValue := 0;
TheFloat.StopValue := 100;
TheFloat.StartFromCurrent := false;
TheFloat.start;
while not KillAnimation do
application.handlemessage;
TheFloat.stop;
end).start;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Image1.Bitmap.LoadFromFile('c:\sample\startimage.png');
Image2.Bitmap.LoadFromFile('c:\sample\startimage.png');
end;
procedure TForm1.BtnStartClick(Sender: TObject);
begin
KillAnimation := false;
createthread(Image1, 'c:\sample\endimage.png');
createthread(Image2, 'c:\sample\endimage.png');
end;
procedure TForm1.BtnResetClick(Sender: TObject);
begin
KillAnimation := false;
Image1.Bitmap.LoadFromFile('c:\sample\startimage.png');
Image2.Bitmap.LoadFromFile('c:\sample\startimage.png');
end;
end.
我原以为在线程中创建Transition和FloatAnimation意味着它们会在完成时被销毁,因为FreeOnTerminate是True。
当我尝试使用“image1.bitmap.loadfromfile”重置图像时,它不会改变。
图像为170 x 170 png文件。
我在这里做错了什么?
我的目标是将TImage和一个图像文件传递给线程,让它动画直到被告知停止。我不太可能需要所有24张图像来制作动画,但你永远不会知道。
道歉,如果我不应该发布我的样本中的所有代码。至少你可以看到一切正在发生。
答案 0 :(得分:3)
你根本不应该使用线程。 UI元素(包括视觉效果)应仅在主UI线程中使用。除非您正在为移动平台开发应用程序,否则对象在超出范围时不会自动销毁,您必须在使用它们时自行销毁它们,或者为它们分配一个将为您销毁它们的所有者。 / p>
请改为尝试:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Objects, FMX.Controls.Presentation,
FMX.StdCtrls, FMX.Ani, FMX.Effects, FMX.Filter.Effects;
type
TForm1 = class(TForm)
Image1: TImage;
Image2: TImage;
BtnStop: TButton;
BtnStart: TButton;
BtnReset: TButton;
procedure BtnStopClick(Sender: TObject);
procedure BtnStartClick(Sender: TObject);
procedure BtnResetClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
Float1: TFloatAnimation;
Float2: TFloatAnimation;
function PrepareEffect(TheImage: TImage; const TargetBMP: String): TFloatAnimation;
procedure ResetImages;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.BtnResetClick(Sender: TObject);
begin
ResetImages;
end;
procedure TForm1.BtnStartClick(Sender: TObject);
begin
Float1.start;
Float2.start;
end;
procedure TForm1.BtnStopClick(Sender: TObject);
begin
Float1.stop;
Float2.stop;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ResetImages;
Float1 := PrepareEffect(Image1, 'c:\sample\endimage.png');
Float2 := PrepareEffect(Image2, 'c:\sample\endimage.png');
end;
function TForm1.PrepareEffect(TheImage: TImage; const TargetBMP: String): TFloatAnimation;
var
Wiggle: TWiggleTransitionEffect;
TheFloat: TFloatAnimation;
begin
Wiggle := TWiggleTransitionEffect.Create(Self);
Wiggle.RandomSeed := 0.3;
Wiggle.Progress := 0;
Wiggle.Parent := TheImage;
Wiggle.Target.LoadFromFile(TargetBMP);
TheFloat := TFloatAnimation.Create(Self);
TheFloat.Parent := Wiggle;
TheFloat.PropertyName := 'Progress';
TheFloat.Duration := 2;
TheFloat.AutoReverse := true;
TheFloat.Loop := true;
TheFloat.StartValue := 0;
TheFloat.StopValue := 100;
TheFloat.StartFromCurrent := false;
Result := TheFloat;
end;
procedure TForm1.ResetImages;
begin
Image1.Bitmap.LoadFromFile('c:\sample\startimage.png');
Image2.Bitmap.LoadFromFile('c:\sample\startimage.png');
end;
end.