gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 15:55:08 27 4
gpt4 key购买 nike

在我的自定义组件中,我创建了一些 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;

最佳答案

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

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

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

  • 表单拥有这些操作,因此它会将它们添加到其声明的已发布部分,并在流处理过程中自动创建它们。要解决此问题,您可以通过覆盖操作的 WriteState 方法来禁用流式传输并跳过继承的行为。
  • 由于您没有编写状态,因此不会保留任何属性。为了避免用户感到困惑,您应该切换使操作从 TCustomAction 而不是 TAction 下降,这样它就不会暴露任何内容。可能有办法让 Action 流正常,但你没有说是否有必要。
  • 您需要注册免费通知,以防表单在此之前释放操作。
  • 如果有人在操作名称上放置了多个组件,则会发生冲突。有多种方法可以处理这个问题,但最干净的方法可能是重写组件的 SetName 方法并使用其名称作为操作名称的前缀。如果这样做,您需要将 RegisterNoIcon 与新类一起使用,这样它们就不会显示在表单上。
  • 在 IDE 的“结构” Pane 中,操作将直接显示在表单下方,而不是像 ActionList 那样嵌套显示。我还没有找到解决办法; SetSubComponentGetParentComponent/HasParentGetChildren 都没有任何效果,因此这可能是硬编码行为。您也可以从结构 Pane 中删除操作,与组件分开。

我确信它可以改进,但这无需任何自定义属性编辑器即可工作:

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;

关于delphi - 如何使子组件 TAction-s 在设计时可用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8652072/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com