我有一个需要计时器的课程。该类必须同时使用 VCL 和 FMX。不幸的是,FMX 定时器是在 中声明的,FMX.Types
而 VCL 定时器是在Vcl.ExtCtrls
.
由于没有条件定义,例如{$IFDEF FMX}xxx{$ENDIF}
如何在跨平台类中使用计时器?
我有一个需要计时器的课程。该类必须同时使用 VCL 和 FMX。不幸的是,FMX 定时器是在 中声明的,FMX.Types
而 VCL 定时器是在Vcl.ExtCtrls
.
由于没有条件定义,例如{$IFDEF FMX}xxx{$ENDIF}
如何在跨平台类中使用计时器?
如果是我,我会编写一个独立于 FMX 和 VCL 框架的专用跨平台计时器类。从概念上讲,它将与 Delphi RTL 处于同一级别。
如果您不想这样做并且想重用现有的计时器类,那么您就处于绑定状态。对于没有 VCL 的目标,你会怎么做?您无法知道您的代码是否会被 FMX 或 VCL 项目使用。想想看。您可以将您的单元编译为 .dcu 并将其包含在任何项目中。在编译单元时,它无法知道最终将使用它的项目类型。
那么该怎么办?您可以在任何地方使用 FMX 计时器。但这迫使 FMX 进入 VCL 项目。我知道我不会喜欢那样的。您可以在 Windows 以外的任何地方使用 FMX 计时器,并在那里使用 VCL 计时器。但这会迫使 VCL 进入 Windows FMX 项目。
所以你可能会采取这种方法:
SetTimer
和KillTimer
.我们可以假设您的类是非可视的,而且它不是设计时组件。如果不是这种情况,那么它将无法与 FMX 和 VCL 兼容。
在这种情况下,没有理由不能包含FMX.Types
在 VCL 应用程序中,也没有理由不能FMX.Types.TTimer
在 VCL 应用程序中创建 - 您根本无法在设计时进行(即:将 FMXTTimer
放在 VCL 表单上)。如果您只需要内部计时器,那么答案很明确 - 只需使用 FMX 计时器,因为无论平台目标或正在使用的框架如何,它都会编译。
unit FMXTimerInVCLApplication;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
FMX.Types;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
FTimer : TTimer; // FMX.Types.TTimer !
procedure foo(Sender : TObject);
end;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FTimer := TTimer.Create(nil);
FTimer.Interval := 1000;
FTimer.OnTimer := foo;
end;
procedure TForm1.foo(Sender : TObject);
begin
ShowMessage('foo');
end;
end.
当然,这确实会给您的应用程序带来相当多的 FMX 包袱。如果您关心这种事情,那么计时器会很臃肿。我将它作为另一个自然答案(正在编写您自己的答案)的替代方案。
TTimer
是一个组件,因此支持接口。我使用一个插入器类将一个 ITimer 接口注入到原始计时器类中,并且只针对这个接口进行编程(这对于两个TTimer
类都是通用的)。
unit Mv.TimerIntf;
interface
uses
System.Classes;
type
ITimer = interface
function PropGetEnabled: Boolean;
function PropGetInterval: Cardinal;
function PropGetOnTimer: TNotifyEvent;
procedure PropSetEnabled(AValue: Boolean);
procedure PropSetInterval(AValue: Cardinal);
procedure PropSetOnTimer(AValue: TNotifyEvent);
property Enabled: Boolean read PropGetEnabled write PropSetEnabled;
property Interval: Cardinal read PropGetInterval write PropSetInterval;
property OnTimer: TNotifyEvent read PropGetOnTimer write PropSetOnTimer;
end;
implementation
end.
和
unit Mv.VCL.Interposer.Timer;
interface
uses
Mv.TimerIntf,
System.Classes,
VCL.ExtCtrls;
type
TTimer = class(VCL.ExtCtrls.TTimer, ITimer)
function PropGetEnabled: Boolean;
function PropGetInterval: Cardinal;
function PropGetOnTimer: TNotifyEvent;
procedure PropSetEnabled(AValue: Boolean);
procedure PropSetInterval(AValue: Cardinal);
procedure PropSetOnTimer(AValue: TNotifyEvent);
end;
implementation
function TTimer.PropGetEnabled: Boolean;
begin
Result := Enabled;
end;
function TTimer.PropGetInterval: Cardinal;
begin
Result := Interval;
end;
function TTimer.PropGetOnTimer: TNotifyEvent;
begin
Result := OnTimer;
end;
procedure TTimer.PropSetEnabled(AValue: Boolean);
begin
Enabled := AValue;
end;
procedure TTimer.PropSetInterval(AValue: Cardinal);
begin
Interval := AValue;
end;
procedure TTimer.PropSetOnTimer(AValue: TNotifyEvent);
begin
OnTimer := AValue;
end;
end.
...
用法:针对接口的代码:
procedure InitTimer(ATimer: ITimer)
begin
ATimer.Interval := 100;
ATimer.OnTimer := DoWhatEver;
end;
...
uses
Vcl.ExtCtrls,
Mv.VCL.Interposer.Timer;
type
TForm1 = class(TForm)
Timer1: TTimer;
end;
//...
begin
InitTimer(Timer1);
end;