首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使子组件TAction-s在设计时可用?

如何使子组件TAction-s在设计时可用?
EN

Stack Overflow用户
提问于 2011-12-28 13:06:03
回答 3查看 1.6K关注 0票数 3

在我的自定义组件中,我创建了一些TAction-s作为子组件。它们都是发布的,但我不能在设计时分配它们,因为它们不能通过对象检查器获得。

如何通过对象检查器使它们“可迭代”?我尝试将操作的所有者设置为自定义组件(宿主窗体)的所有者,但没有成功。

编辑:看起来Embarcadero改变了与这个问题相关的Delphi IDE行为。如果你使用的是Delphi以前的XE版本,你应该使用我自己的答案中的解决方案。对于XE和更高版本,您应该使用Craig Peterson提供的解决方案。

编辑:我添加了我自己的答案来解决这个问题,例如,通过在我的自定义组件中创建一个TCustomActionList实例,并将其所有者设置为宿主窗体(自定义组件的所有者)。然而,我对这个解决方案不太满意,因为我认为TCustomActionList的实例有点多余。所以我仍然希望得到更好的解决方案。

编辑:添加代码示例

代码语言:javascript
复制
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;
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-04 06:59:29

据我所知,你不应该那样做。

完成所需操作的最简单方法是创建可与任何TVrlFormCore组件一起使用的新独立操作,并在HandlesTarget回调中设置目标对象。请看StdActns.pas中的示例。当某人将你的组件放到表单上时,这些操作不会自动可用,但他们可以使用新标准操作...命令手动将它们添加到他们的操作列表中。有一篇关于注册标准操作here的好文章。

如果您确实希望自动创建操作,则需要将操作Owner属性设置为表单,并设置Name属性。这些都是必要的,但它确实引入了一系列您需要解决的问题:

  • 表单拥有这些操作,因此它会将它们添加到声明的已发布部分,并在流式处理过程中自动创建它们。要解决这个问题,您可以通过覆盖操作的WriteState方法来禁用流式传输,并跳过继承的行为。
  • 由于您不是在编写状态,因此不会持久化任何属性。为了避免混淆您的用户,您应该切换使操作从TCustomAction而不是TAction下降,这样它就不会公开任何东西。也许有办法让动作流正确,但你没有说这是否是necessary.
  • You需要注册免费通知,以防表单在你之前释放动作。
  • 如果有人在动作名称上删除了多个组件,将会发生冲突。有多种方法可以处理这种情况,但最干净的方法可能是覆盖组件的SetName方法,并将其名称用作操作名称的前缀。如果这样做,您需要对新类使用RegisterNoIcon,这样它们就不会显示在窗体上。
  • 在集成开发环境的结构窗格中,操作将直接显示在窗体下面,而不是像ActionList所显示的那样嵌套。我还没有找到解决这个问题的方法;SetSubComponentGetParentComponent/HasParentGetChildren都没有任何影响,所以这可能是硬编码行为。您也可以从结构窗格中删除操作,该操作也独立于组件。

我相信它是可以改进的,但它不需要任何自定义属性编辑器就可以工作:

代码语言:javascript
复制
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;
票数 2
EN

Stack Overflow用户

发布于 2012-01-05 16:35:56

编辑:将此解决方案用于Delphi XE之前的Delphi版本。对于XE和更高版本,请使用Craig Peterson answer (不需要冗余TCustomActionList实例)。

在使用了来自Craig Peterson's answer的信息之后,我决定在我的自定义组件中实例化一个TCustomActionList。到目前为止,这是在Object Inspector中获取操作列表的唯一方法。

代码如下:

代码语言:javascript
复制
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;
票数 1
EN

Stack Overflow用户

发布于 2011-12-31 16:21:58

您不能指定它们,因为它们被设计为只读:

代码语言:javascript
复制
property DefaultAction: TBasicAction read FDefaultAction; 
property CancelAction : TBasicAction read FCancelAction; 
property EditAction   : TBasicAction read FEditAction; 

您应该将类的接口更改为:

代码语言:javascript
复制
property DefaultAction: TBasicAction read FDefaultAction write FDefaultAction; 
property CancelAction : TBasicAction read FCancelAction write FCancelAction; 
property EditAction   : TBasicAction read FEditAction write FEditAction; 

或者为每个操作编写适当的setter。

编辑:

你需要的是

  1. 来实现你的3个自定义动作作为Predefined Actions (示例见StdActns.pas )。
  2. 通过调用ActnList.RegisterActions来注册它们。(参见RAD Studio documentation)
  3. to向表单添加TActionList和/或TActionManager,以允许您的Predefined Actions出现在每个TControl子程序的操作列表编辑器中的预定义操作列表中。

你可以在谷歌上广泛搜索这个主题,并找到一些具体的例子。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8652072

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档