问题描述
我有一个 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.
通过使用将每个适配器与 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 onlyTMyComponentUIControl_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上,除非设置属性分配给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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!