在我的自定义组件中,我创建了一些TAction-s作为子组件。它们都是发布的,但我不能在设计时分配它们,因为它们不能通过对象检查器获得。
如何通过对象检查器使它们“可迭代”?我尝试将操作的所有者设置为自定义组件(宿主窗体)的所有者,但没有成功。
编辑:看起来Embarcadero改变了与这个问题相关的Delphi IDE行为。如果你使用的是Delphi以前的XE版本,你应该使用我自己的答案中的解决方案。对于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;发布于 2012-01-04 06:59:29
据我所知,你不应该那样做。
完成所需操作的最简单方法是创建可与任何TVrlFormCore组件一起使用的新独立操作,并在HandlesTarget回调中设置目标对象。请看StdActns.pas中的示例。当某人将你的组件放到表单上时,这些操作不会自动可用,但他们可以使用新标准操作...命令手动将它们添加到他们的操作列表中。有一篇关于注册标准操作here的好文章。
如果您确实希望自动创建操作,则需要将操作Owner属性设置为表单,并设置Name属性。这些都是必要的,但它确实引入了一系列您需要解决的问题:
WriteState方法来禁用流式传输,并跳过继承的行为。TCustomAction而不是TAction下降,这样它就不会公开任何东西。也许有办法让动作流正确,但你没有说这是否是necessary.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;发布于 2012-01-05 16:35:56
编辑:将此解决方案用于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;发布于 2011-12-31 16:21:58
您不能指定它们,因为它们被设计为只读:
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。
编辑:
你需要的是
StdActns.pas )。ActnList.RegisterActions来注册它们。(参见RAD Studio documentation)TActionList和/或TActionManager,以允许您的Predefined Actions出现在每个TControl子程序的操作列表编辑器中的预定义操作列表中。你可以在谷歌上广泛搜索这个主题,并找到一些具体的例子。
https://stackoverflow.com/questions/8652072
复制相似问题