2

我有一个需要计时器的课程。该类必须同时使用 VCL 和 FMX。不幸的是,FMX 定时器是在 中声明的,FMX.Types而 VCL 定时器是在Vcl.ExtCtrls.

由于没有条件定义,例如{$IFDEF FMX}xxx{$ENDIF}如何在跨平台类中使用计时器?

4

3 回答 3

4

如果是我,我会编写一个独立于 FMX 和 VCL 框架的专用跨平台计时器类。从概念上讲,它将与 Delphi RTL 处于同一级别。

如果您不想这样做并且想重用现有的计时器类,那么您就处于绑定状态。对于没有 VCL 的目标,你会怎么做?您无法知道您的代码是否会被 FMX 或 VCL 项目使用。想想看。您可以将您的单元编译为 .dcu 并将其包含在任何项目中。在编译单元时,它无法知道最终将使用它的项目类型。

那么该怎么办?您可以在任何地方使用 FMX 计时器。但这迫使 FMX 进入 VCL 项目。我知道我不会喜欢那样的。您可以在 Windows 以外的任何地方使用 FMX 计时器,并在那里使用 VCL 计时器。但这会迫使 VCL 进入 Windows FMX 项目。

所以你可能会采取这种方法:

  1. 创建您自己的跨平台计时器类。
  2. 在 Windows 以外的平台上,在 FMX 计时器之上实现它。
  3. 在 Windows 上使用原始 Windows API 函数SetTimerKillTimer.
于 2015-09-15T12:41:05.497 回答
1

我们可以假设您的类是非可视的,而且它不是设计时组件。如果不是这种情况,那么它将无法与 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 包袱。如果您关心这种事情,那么计时器会很臃肿。我将它作为另一个自然答案(正在编写您自己的答案)的替代方案。

于 2015-09-15T11:01:10.593 回答
0

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;
于 2022-02-06T18:12:56.253 回答