在 FireMonkey 组件内部使用 Tedit
Using Tedit Inside of a FireMonkey component
我在 Fire-monkey 中创建了一个组件,并在其中创建了一个 TEdit。
我的组件有一个名为 Value 的字符串 属性,通过向它输出任何字符串,我的组件将在 Tedit 中显示它。
在设计时,一切都很好。但在 运行 时间,Tedit 中没有显示任何内容
我的代码是
type
TMyComponent = class(TPanel)
private
{ Private declarations }
Edit:TEdit;
FValue:String;
Procedure SetValue(Const Value:String);
protected
{ Protected declarations }
Constructor Create(Aoner:TComponent); Override;
Destructor Destroy; Override;
public
{ Public declarations }
published
{ Published declarations }
Property Value:String Read FValue Write SetValue;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TMyComponent]);
end;
Constructor TMyComponent.Create(Aoner:TComponent);
begin
Inherited;
Width:=100;
Height:=100;
Edit:=TEdit.Create(Self);
Edit.Parent:=Self;
Edit.Width:=30;
Edit.Text:='';
Edit.Align:=TAlignLayout.Scale;
end;
Procedure TMyComponent.SetValue(const Value: string);
begin
FValue:=Value;
Edit.Text:=FValue;
end;
Destructor TMyComponent.Destroy;
begin
Edit.Destroy;
Inherited Destroy;
end;
end.
我该怎么办?
您应该使用 FireMonkey 中的样式来执行此类操作,因此对于您的示例,您需要 MyComponent.style
文件如下
object TRectangle
StyleName = 'MyComponentStyle'
Align = Center
Fill.Color = xFFF0F0F0
HitTest = False
Size.Width = 159.000000000000000000
Size.Height = 131.000000000000000000
Size.PlatformDefault = False
Stroke.Color = xFFCCCCCC
object TEdit
StyleName = 'MyComponentEditStyle'
Touch.InteractiveGestures = [LongTap, DoubleTap]
Align = Scale
TabOrder = 0
Size.Width = 79.499755859375000000
Size.Height = 21.833337783813480000
Size.PlatformDefault = False
end
end
那么你需要在项目文件中包含MyComponent.rc
如下
MyComponentStyle RCDATA "MyComponent.style"
你的MyComponent.pas
将是
unit MyComponent;
interface
uses System.Classes, FMX.Types, FMX.Controls, FMX.StdCtrls, FMX.Edit, FMX.Styles;
type
TMyComponent = class(TPanel)
private
{ Private declarations }
FEdit: TEdit;
FValue: string;
procedure SetValue(const AValue: string);
function GetValue: string;
protected
{ Protected declarations }
procedure FreeStyle; override;
procedure ApplyStyle; override;
function GetStyleObject: TFmxObject; override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
property Value: string read GetValue write SetValue;
end;
procedure Register;
implementation
uses Winapi.Windows;
{$R MyComponent.res}
procedure Register;
begin
RegisterComponents('Samples', [TMyComponent]);
end;
procedure TMyComponent.ApplyStyle;
begin
inherited;
if FindStyleResource<TEdit>('MyComponentEditStyle', FEdit) then
begin
FEdit.Visible := True;
FEdit.Text := Value;
end;
end;
function TMyComponent.GetStyleObject: TFmxObject;
const
Style = 'MyComponentStyle';
begin
if (StyleLookup = '') then
Result := TStyleStreaming.LoadFromResource(HInstance, Style, RT_RCDATA)
else
Result := inherited GetStyleObject;
end;
procedure TMyComponent.FreeStyle;
begin
FEdit := nil;
inherited;
end;
constructor TMyComponent.Create(AOwner: TComponent);
begin
inherited;
Width := 100;
Height := 100;
end;
procedure TMyComponent.SetValue(const AValue: string);
begin
FValue := AValue;
if Assigned(FEdit) then
begin
FEdit.Text := FValue;
end;
end;
function TMyComponent.GetValue: string;
begin
Result := FValue;
end;
end.
最初我以为您在运行时创建和使用组件时遇到了问题。在运行时实例化和使用您的组件完全没问题。
在 EugeneK 的评论之后,我现在明白如果您在设计时实例化它并尝试在运行时更改 TEdit
的文本 属性,则该组件不起作用。
原因可以追溯到这样一个事实,即您的组件是一个组合类型并由子组件构成(好吧,只有一个 TEdit
)。如果子组件的 Stored
属性 未设置为 False
,它们可能会在设计时流式传输多次,f.ex。当您在表单的表单视图和文本视图之间切换时。
查看 documentation 并向下滚动到 TCalender:构造复杂性,您可以在其中找到以下内容:
Every object in the component tree has its Stored property set to
False and its Locked property set to True. Disabling Stored prevents
the object from being streamed out to the .fmx file by the Form
Designer. If the Stored property is not disabled, subcomponents would
be redundantly created when loading.
两次将表单视图切换到文本视图后的结果:
object MyComponent1: TMyComponent
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 100.000000000000000000
Size.Height = 100.000000000000000000
Size.PlatformDefault = False
TabOrder = 5
object TEdit
Touch.InteractiveGestures = [LongTap, DoubleTap]
Align = Scale
TabOrder = 1
Size.Width = 90.000000000000000000
Size.Height = 18.333332061767580000
Size.PlatformDefault = False
end
object TEdit
Touch.InteractiveGestures = [LongTap, DoubleTap]
Align = Scale
TabOrder = 0
Size.Width = 90.000000000000000000
Size.Height = 18.333332061767580000
Size.PlatformDefault = False
end
end
虽然它应该是这样的:
object MyComponent1: TMyComponent
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 100.000000000000000000
Size.Height = 100.000000000000000000
Size.PlatformDefault = False
TabOrder = 5
end
多余的 TEdit
控件将覆盖您在构造函数中创建的控件。
对您的代码的更正:
添加标记行
constructor TMyComponent.Create(Aoner: TComponent);
begin
inherited;
Width:=100;
Height:=100;
Edit:=TEdit.Create(Self);
Edit.Parent:=Self;
Edit.Width:=90;
Edit.Align:=TAlignLayout.Scale;
Edit.Stored := False; // *** add this line ***
end;
我在 Fire-monkey 中创建了一个组件,并在其中创建了一个 TEdit。 我的组件有一个名为 Value 的字符串 属性,通过向它输出任何字符串,我的组件将在 Tedit 中显示它。 在设计时,一切都很好。但在 运行 时间,Tedit 中没有显示任何内容 我的代码是
type
TMyComponent = class(TPanel)
private
{ Private declarations }
Edit:TEdit;
FValue:String;
Procedure SetValue(Const Value:String);
protected
{ Protected declarations }
Constructor Create(Aoner:TComponent); Override;
Destructor Destroy; Override;
public
{ Public declarations }
published
{ Published declarations }
Property Value:String Read FValue Write SetValue;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TMyComponent]);
end;
Constructor TMyComponent.Create(Aoner:TComponent);
begin
Inherited;
Width:=100;
Height:=100;
Edit:=TEdit.Create(Self);
Edit.Parent:=Self;
Edit.Width:=30;
Edit.Text:='';
Edit.Align:=TAlignLayout.Scale;
end;
Procedure TMyComponent.SetValue(const Value: string);
begin
FValue:=Value;
Edit.Text:=FValue;
end;
Destructor TMyComponent.Destroy;
begin
Edit.Destroy;
Inherited Destroy;
end;
end.
我该怎么办?
您应该使用 FireMonkey 中的样式来执行此类操作,因此对于您的示例,您需要 MyComponent.style
文件如下
object TRectangle
StyleName = 'MyComponentStyle'
Align = Center
Fill.Color = xFFF0F0F0
HitTest = False
Size.Width = 159.000000000000000000
Size.Height = 131.000000000000000000
Size.PlatformDefault = False
Stroke.Color = xFFCCCCCC
object TEdit
StyleName = 'MyComponentEditStyle'
Touch.InteractiveGestures = [LongTap, DoubleTap]
Align = Scale
TabOrder = 0
Size.Width = 79.499755859375000000
Size.Height = 21.833337783813480000
Size.PlatformDefault = False
end
end
那么你需要在项目文件中包含MyComponent.rc
如下
MyComponentStyle RCDATA "MyComponent.style"
你的MyComponent.pas
将是
unit MyComponent;
interface
uses System.Classes, FMX.Types, FMX.Controls, FMX.StdCtrls, FMX.Edit, FMX.Styles;
type
TMyComponent = class(TPanel)
private
{ Private declarations }
FEdit: TEdit;
FValue: string;
procedure SetValue(const AValue: string);
function GetValue: string;
protected
{ Protected declarations }
procedure FreeStyle; override;
procedure ApplyStyle; override;
function GetStyleObject: TFmxObject; override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
property Value: string read GetValue write SetValue;
end;
procedure Register;
implementation
uses Winapi.Windows;
{$R MyComponent.res}
procedure Register;
begin
RegisterComponents('Samples', [TMyComponent]);
end;
procedure TMyComponent.ApplyStyle;
begin
inherited;
if FindStyleResource<TEdit>('MyComponentEditStyle', FEdit) then
begin
FEdit.Visible := True;
FEdit.Text := Value;
end;
end;
function TMyComponent.GetStyleObject: TFmxObject;
const
Style = 'MyComponentStyle';
begin
if (StyleLookup = '') then
Result := TStyleStreaming.LoadFromResource(HInstance, Style, RT_RCDATA)
else
Result := inherited GetStyleObject;
end;
procedure TMyComponent.FreeStyle;
begin
FEdit := nil;
inherited;
end;
constructor TMyComponent.Create(AOwner: TComponent);
begin
inherited;
Width := 100;
Height := 100;
end;
procedure TMyComponent.SetValue(const AValue: string);
begin
FValue := AValue;
if Assigned(FEdit) then
begin
FEdit.Text := FValue;
end;
end;
function TMyComponent.GetValue: string;
begin
Result := FValue;
end;
end.
最初我以为您在运行时创建和使用组件时遇到了问题。在运行时实例化和使用您的组件完全没问题。
在 EugeneK 的评论之后,我现在明白如果您在设计时实例化它并尝试在运行时更改 TEdit
的文本 属性,则该组件不起作用。
原因可以追溯到这样一个事实,即您的组件是一个组合类型并由子组件构成(好吧,只有一个 TEdit
)。如果子组件的 Stored
属性 未设置为 False
,它们可能会在设计时流式传输多次,f.ex。当您在表单的表单视图和文本视图之间切换时。
查看 documentation 并向下滚动到 TCalender:构造复杂性,您可以在其中找到以下内容:
Every object in the component tree has its Stored property set to False and its Locked property set to True. Disabling Stored prevents the object from being streamed out to the .fmx file by the Form Designer. If the Stored property is not disabled, subcomponents would be redundantly created when loading.
两次将表单视图切换到文本视图后的结果:
object MyComponent1: TMyComponent
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 100.000000000000000000
Size.Height = 100.000000000000000000
Size.PlatformDefault = False
TabOrder = 5
object TEdit
Touch.InteractiveGestures = [LongTap, DoubleTap]
Align = Scale
TabOrder = 1
Size.Width = 90.000000000000000000
Size.Height = 18.333332061767580000
Size.PlatformDefault = False
end
object TEdit
Touch.InteractiveGestures = [LongTap, DoubleTap]
Align = Scale
TabOrder = 0
Size.Width = 90.000000000000000000
Size.Height = 18.333332061767580000
Size.PlatformDefault = False
end
end
虽然它应该是这样的:
object MyComponent1: TMyComponent
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 100.000000000000000000
Size.Height = 100.000000000000000000
Size.PlatformDefault = False
TabOrder = 5
end
多余的 TEdit
控件将覆盖您在构造函数中创建的控件。
对您的代码的更正: 添加标记行
constructor TMyComponent.Create(Aoner: TComponent);
begin
inherited;
Width:=100;
Height:=100;
Edit:=TEdit.Create(Self);
Edit.Parent:=Self;
Edit.Width:=90;
Edit.Align:=TAlignLayout.Scale;
Edit.Stored := False; // *** add this line ***
end;