如何使单个组件同时支持VCL和FMX? [英] How to make a single component support both VCL and FMX?

查看:116
本文介绍了如何使单个组件同时支持VCL和FMX?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 TComponent 来控制某些UI。此组件旨在通过使用条件支持VCL和Firemonkey。这些条件指示我的组件是接受VCL控件还是FMX控件。目前,我们期望在应用程序级别定义此条件,以在运行时指示组件是否要管理VCL或FMX控件。

I have a TComponent which controls some of the UI. This component is designed to support both VCL and Firemonkey by using conditionals. Such conditionals instruct my component whether to accept a VCL control or an FMX control. It's currently expected that this conditional is defined on the application level to instruct the component in run-time whether it's to manage a VCL or FMX control.

我想将我的组件发布到IDE中,同时支持VCL和FMX,并与条件共享同一单元。但是,取决于当前使用的是VCL还是FMX,属性名称/类型有所不同。

I'd like to publish my component into the IDE with support for both VCL and FMX, sharing the same unit with conditionals. However, depending on whether VCL or FMX is currently in use, the property names/types differ.

例如...

type
  TMyComponent = class(TComponent)
  published
    {$IFDEF USE_FMX}
    property TabControl: TTabControl read FTabControl write SetTabControl;
    {$ENDIF}
    {$IFDEF USE_VCL}
    property PageControl: TPageControl read FPageControl write SetPageControl;
    {$ENDIF}
  end;

我的目标是能够将此非可视组件拖放到VCL或FMX表单上,并在对象检查器中自动显示适当的特定于框架的属性。

My goal is to be able to drop this non-visual component onto either a VCL or FMX form, and automatically show the appropriate framework-specific properties in the object inspector.

如何注册通过条件共享VCL和FMX代码的组件?

How do I go about registering this component which shares both VCL and FMX code via conditionals?

推荐答案

我强烈建议反对像尝试创建的那样创建特定于框架的属性。我建议改为创建单独的特定于框架的适配器组件,然后根据需要将这些适配器之一分配给您的主组件,例如:

I would strongly advise against creating framework-specific properties like you are trying to do. I would suggest instead creating separate framework-specific adapter components, and then you can assign one of those adapters to your main component as needed, eg:

unit MyComponentUI;

interface

uses
  Classes;

type
  TMyComponentUIControl = class(TComponent)
  public
    procedure DoSomethingWithControl; virtual; abstract;
    ...
  end;

implementation

...

end.



unit MyComponentFmxUI;

uses
  MyComponentUI,
  FMX.TabControl;

type
  TMyComponentUIControl_FMXTabControl = class(TMyComponentUIControl)
  private
    FTabControl: TTabControl;
    procedure SetTabControl(Value: TTabControl);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    procedure DoSomethingWithControl; override;
  published
    property TabControl: TTabControl read FTabControl write SetTabControl;
  end;

procedure Register;

implementation

uses
  FMX.Controls;

procedure TMyComponentUIControl_FMXTabControl.DoSomethingWithControl; 
begin
  if FTabControl <> nil then
  begin
    ...
  end;
end;

procedure TMyComponentUIControl_FMXTabControl.SetTabControl(Value: TTabControl);
begin
  if FTabControl <> Value then
  begin
    if FTabControl <> nil then FTabControl.RemoveFreeNotification(Self);
    FTabControl := Value;
    if FTabControl <> nil then FTabControl.FreeNotification(Self);
  end;
end;

procedure TMyComponentUIControl_FMXTabControl.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent = FTabControl) then
    FTabControl := nil;
end;

procedure Register;
begin
  GroupDescendantsWith(TMyComponentUIControl_FMXTabControl, TControl);
  RegisterComponents('My Component', [TMyComponentUIControl_FMXTabControl]);
end;

end.



unit MyComponentVclUI;

interface

uses
  MyComponentUI,
  Vcl.ComCtrls;

type
  TMyComponentUIControl_VCLPageControl = class(TMyComponentUIControl)
  private
    FPageControl: TPageControl;
    procedue SetPageControl(Value: TPageControl);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    procedure DoSomethingWithControl; override;
  published
    property PageControl: TPageControl read FPageControl write SetPageControl;
  end;

procedure Register;

implementation

uses
  Vcl.Controls;

procedure TMyComponentUIControl_VCLPageControl.DoSomethingWithControl; 
begin
  if FPageControl <> nil then
  begin
    ...
  end;
end;

procedure TMyComponentUIControl_VCLPageControl.SetPageControl(Value: TPageControl);
begin
  if FPageControl <> Value then
  begin
    if FPageControl <> nil then FPageControl.RemoveFreeNotification(Self);
    FPageControl := Value;
    if FPageControl <> nil then FPageControl.FreeNotification(Self);
  end;
end;

procedure TMyComponentUIControl_VCLPageControl.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent = FPageControl) then
    FPageControl := nil;
end;

procedure Register;
begin
  GroupDescendantsWith(TMyComponentUIControl_VCLPageControl, TControl);
  RegisterComponents('My Component', [TMyComponentUIControl_VCLPageControl]);
end;

end.



unit MyComponent;

interface

uses
  Classes,
  MyComponentUI;

type
  TMyComponent = class(TComponent)
  private
    FUIControl: TMyComponentUIControl;
    procedure SetUIControl(Value: TMyComponentUIControl);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    procedure DoSomething;
  published
    property UIControl: TMyComponentUIControl read FUIControl write SetUIControl;
  end;

procedure Register;

implementation

procedure TMyComponent.DoSomething;
begin
  ...
  if FUIControl <> nil then
    FUIControl.DoSomethingWithControl;
  ...
end;

procedure TMyComponent.SetUIControl(Value: TMyComponentUIControl);
begin
  if FUIControl <> Value then
  begin
    if FUIControl <> nil then FUIControl.RemoveFreeNotification(Self);
    FUIControl := Value;
    if FUIControl <> nil then FUIControl.FreeNotification(Self);
  end;
end;

procedure TMyComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent = FUIControl) then
    FUIControl := nil;
end;

procedure Register;
begin
  RegisterComponents('My Component', [TMyComponent]);
end;

end.

通过使用 GroupDescendentsWith() 将每个适配器与 FMX.Controls.TControl分组 Vcl.Controls.TControl ,这允许IDE在设计时根据父项目中使用的框架过滤组件:

By using GroupDescendentsWith() to group each adapter with either FMX.Controls.TControl or Vcl.Controls.TControl, this allows the IDE to filter the components at design-time based on framework used in the parent project:

在VCL表单设计器上,工具面板中仅会显示
TMyComponentUIControl_VCLPageControl

On a VCL Form Designer, you will see only TMyComponentUIControl_VCLPageControl available in the Tool Palette.

在FMX表单设计器上,工具面板中将仅显示 TMyComponentUIControl_FMXTabControl

On a FMX Form Designer, you will see only TMyComponentUIControl_FMXTabControl available in the Tool Palette.

在DataModule Designer上,除非设置 TDataModule.ClassGroup 属性分配给VCL或FMX组。然后,您将在工具面板中看到相应的适配器。

On a DataModule Designer, you will not see either adapter, unless you set the TDataModule.ClassGroup property to a VCL or FMX group. Then you will see the appropriate adapter available in the Tool Palette.

这篇关于如何使单个组件同时支持VCL和FMX?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆