在我的自定义组件中,我创建了一些TAction-s作为子组件。它们都已发布,但我无法在设计时分配它们,因为它们无法通过对象检查器获得。
如何让对象检查员“迭代”它们?我试图将操作的所有者设置为自定义组件的所有者(托管表单),但没有成功。
编辑:看起来Embarcadero改变了与此问题相关的Delphi IDE行为。如果你在XE之前使用Delphi版本,你应该使用我自己答案的解决方案。对于XE及以上版本,您应该使用Craig Peterson的解决方案。 编辑:我添加了自己的答案来解决问题,即在我的自定义组件中创建TCustomActionList实例并将其所有者设置为托管表单(自定义组件的所有者)。但是我对这个解决方案不太满意,因为我认为TCustomActionList的实例是多余的。所以我仍然希望得到更好的解决方案。编辑:添加代码示例
uses
.., ActnList, ..;
type
TVrlFormCore = class(TComponent)
private
FCancelAction: TBasicAction;
FDefaultAction: TBasicAction;
FEditAction: TBasicAction;
protected
procedure DefaultActionExecute(ASender: TObject); virtual;
procedure CancelActionExecute(ASender: TObject); virtual;
procedure EditActionExecute(ASender: TObject); virtual;
public
constructor Create(AOwner: TComponent); override;
published
property DefaultAction: TBasicAction read FDefaultAction;
property CancelAction : TBasicAction read FCancelAction;
property EditAction : TBasicAction read FEditAction;
end;
implementation
constructor TVrlFormCore.Create(AOwner: TComponent);
begin
inherited;
FDefaultAction := TAction.Create(Self);
with FDefaultAction as TAction do
begin
SetSubComponent(True);
Caption := 'OK';
OnExecute := DefaultActionExecute;
end;
FCancelAction := TAction.Create(Self);
with FCancelAction as TAction do
begin
SetSubComponent(True);
Caption := 'Cancel';
OnExecute := Self.CancelActionExecute;
end;
FEditAction := TAction.Create(Self);
with FEditAction as TAction do
begin
SetSubComponent(True);
Caption := 'Edit';
OnExecute := Self.EditActionExecute;
end;
end;
答案 0 :(得分:2)
据我所知,你不应该这样做。
执行所需操作的简便方法是创建可以与任何TVrlFormCore
组件一起使用的新独立操作,并在HandlesTarget
回调中设置目标对象。请查看 StdActns.pas 中的示例。当sommeone将组件放在表单上时,这些操作将无法自动使用,但是他们可以使用新标准操作... 命令手动将它们添加到操作列表中。有一篇关于注册标准行动的文章here。
如果您确实想要自动创建操作,则需要将操作Owner
属性设置为表单,并且需要设置Name
属性。这就是必要的,但它确实引入了一些你需要解决的问题:
WriteState
方法来禁用流式传输,并跳过继承的行为。 TCustomAction
而不是TAction
下降,因此不会暴露任何内容。可能有办法正确地制作动作流,但你没有说是否有必要。SetSubComponent
,GetParentComponent
/ HasParent
或GetChildren
都不会产生任何影响,因此这可能是硬编码行为。您也可以从结构窗格中删除该操作,也可以从组件中删除。我确信它可以改进,但这没有任何自定义属性编辑器:
type
TVrlAction = class(TCustomAction)
protected
procedure WriteState(Writer: TWriter); override;
end;
TVrlFormCore = class(TComponent)
private
FDefaultAction: TVrlAction;
protected
procedure DefaultActionExecute(ASender: TObject); virtual;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
procedure SetName(const NewName: TComponentName); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
public
property DefaultAction: TVrlAction read FDefaultAction;
end;
procedure Register;
implementation
// TVrlAction
procedure TVrlAction.WriteState(Writer: TWriter);
begin
// No-op
end;
// TVrlFormCore
constructor TVrlFormCore.Create(AOwner: TComponent);
begin
inherited;
FDefaultAction := TVrlAction.Create(AOwner);
with FDefaultAction do
begin
FreeNotification(Self);
Name := 'DefaultAction';
Caption := 'OK';
OnExecute := DefaultActionExecute;
end;
end;
destructor TVrlFormCore.Destroy;
begin
FDefaultAction.Free;
inherited;
end;
procedure TVrlFormCore.DefaultActionExecute(ASender: TObject);
begin
end;
procedure TVrlFormCore.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if Operation = opRemove then
if AComponent = FDefaultAction then
FDefaultAction := nil;
end;
procedure TVrlFormCore.SetName(const NewName: TComponentName);
begin
inherited;
if FDefaultAction <> nil then
FDefaultAction.Name := NewName + '_DefaultAction';
end;
procedure Register;
begin
RegisterComponents('Samples', [TVrlFormCore]);
RegisterNoIcon([TVrlAction]);
end;
答案 1 :(得分:1)
编辑:在Delphi XE之前使用此解决方案用于Delphi版本。对于XE及更高版本,请使用Craig Peterson answer(不需要冗余的TCustomActionList实例)。
在干涉并使用来自Craig Peterson's answer的信息之后,我决定在我的自定义组件中实例化TCustomActionList。到目前为止,这是在Object Inspector中获取操作列表的唯一方法。
以下是代码:
uses
..., ActnList, ...;
type
TVrlAction=class(TCustomAction)
protected
procedure WriteState(Writer: TWriter); override;
published
property Caption;
end;
TVrlActionList=class(TCustomActionList)
protected
procedure WriteState(Writer: TWriter); override;
end;
TVrlFormCore = class(TVrlItemSource)
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure SetName(const NewName: TComponentName); override;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{ TVrlAction }
procedure TVrlAction.WriteState(Writer: TWriter);
begin
end;
{ TVrlActionList }
procedure TVrlActionList.WriteState(Writer: TWriter);
begin
end;
{ TVrlFormCore }
constructor TVrlFormCore.Create(AOwner: TComponent);
begin
inherited;
FActions := TVrlActionList.Create(AOwner);
FDefaultAction := TVrlAction.Create(AOwner);
with FDefaultAction as TVrlAction do
begin
FreeNotification(Self);
Caption := 'OK';
OnExecute := DefaultActionExecute;
end;
FActions.AddAction(TContainedAction(FDefaultAction));
FCancelAction := TVrlAction.Create(AOwner);
with FCancelAction as TVrlAction do
begin
FreeNotification(Self);
Caption := 'Cancel';
OnExecute := Self.CancelActionExecute;
end;
FActions.AddAction(TContainedAction(FCancelAction));
FEditAction := TVrlAction.Create(AOwner);
with FEditAction as TVrlAction do
begin
FreeNotification(Self);
Caption := 'Edit';
OnExecute := Self.EditActionExecute;
end;
FActions.AddAction(TContainedAction(FEditAction));
end;
procedure TVrlFormCore.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if Operation=opRemove then
begin
if AComponent = FMaster then
FMaster := nil
else if (AComponent is TVrlFormCore) then
FDetails.Remove(TVrlFormCore(AComponent))
else if AComponent=FDefaultAction then
FDefaultAction := nil
else if AComponent=FCancelAction then
FCancelAction := nil
else if AComponent=FEditAction then
FEditAction := nil;
end;
end;
procedure TVrlFormCore.SetName(const NewName: TComponentName);
begin
inherited;
if FActions<>nil then
FActions.Name := NewName + '_Actions';
if FDefaultAction <> nil then
FDefaultAction.Name := NewName + '_DefaultAction';
if FCancelAction <> nil then
FCancelAction.Name := NewName + '_CancelAction';
if FEditAction <> nil then
FEditAction.Name := NewName + '_EditAction';
end;
答案 2 :(得分:0)
您无法分配它们,因为它们只能通过设计阅读:
property DefaultAction: TBasicAction read FDefaultAction;
property CancelAction : TBasicAction read FCancelAction;
property EditAction : TBasicAction read FEditAction;
您应该将班级界面更改为:
property DefaultAction: TBasicAction read FDefaultAction write FDefaultAction;
property CancelAction : TBasicAction read FCancelAction write FCancelAction;
property EditAction : TBasicAction read FEditAction write FEditAction;
或为每个动作编写适当的setter。
修改强>
那么你需要的是
将您的3个自定义操作实施为Predefined Actions(有关示例,请参阅StdActns.pas
)。
通过调用ActnList.RegisterActions
来注册它们。 (见RAD Studio documentation)
将TActionList
和/或TActionManager
添加到表单中,以允许您的Predefined Actions
出现在每个TControl后代的操作列表编辑器中的预定义操作列表中。
您可以在Google上对该主题进行大量搜索,并找到一些具体的示例。