3

カスタム コンポーネントで、いくつかの TAction をサブコンポーネントとして作成しました。それらはすべて公開されていますが、オブジェクト インスペクタからは利用できなかったため、設計時に割り当てることができませんでした。

オブジェクトインスペクターでそれらを「反復可能」にするにはどうすればよいですか? アクションの所有者をカスタム コンポーネント (ホスティング フォーム) の所有者に設定しようとしましたが、成功しませんでした。

編集: 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;
4

3 に答える 3

2

私が知る限り、あなたはそのようにするべきではありません。

必要なことを行う簡単な方法は、任意のコンポーネントで動作し、コールバックTVrlFormCoreでターゲット オブジェクトを設定できる新しいスタンドアロン アクションを作成することです。HandlesTarget例については、StdActns.pasを参照してください。コンポーネントをフォームにドロップしてもアクションは自動的に使用可能になりませんが、新しい標準アクション...コマンドを使用してアクション リストに手動で追加できます。ここに標準アクションの登録に関する良い記事があります。

本当にアクションを自動作成したい場合は、アクションOwnerプロパティをフォームに設定し、Nameプロパティを設定する必要があります。必要な作業はこれですべてですが、回避する必要がある多くの問題が発生します。

  • フォームはアクションを所有しているため、宣言の公開セクションにアクションを追加し、ストリーミング プロセスの一部として自動作成します。これを回避するには、アクションのWriteStateメソッドを上書きしてストリーミングを無効にし、継承された動作をスキップします。
  • 状態を書き込んでいないため、どのプロパティも保持されません。ユーザーの混乱を避けるために、アクションを のTCustomAction代わりにから派生させるように切り替えて、TAction何も公開しないようにする必要があります。アクション ストリームを適切に作成する方法があるかもしれませんが、それが必要かどうかは言われませんでした。
  • フォームがアクションを解放する前に、無料の通知に登録する必要があります。
  • 誰かがあなたのコンポーネントを複数ドロップすると、アクション名が競合します。これを処理する方法は複数ありますが、おそらく最もクリーンな方法は、コンポーネントの SetName メソッドをオーバーライドし、その名前をアクション名のプレフィックスとして使用することです。その場合、フォームに表示されないように、新しいクラスで RegisterNoIcon を使用する必要があります。
  • IDE の構造ペインでは、アクションは ActionList のようにネストされるのではなく、フォームのすぐ下に表示されます。私はそれを回避する方法を見つけていません。SetSubComponentGetParentComponent/ 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-03T22:59:29.293 に答える
1

編集: Delphi XE より前のバージョンの Delphi には、このソリューションを使用してください。XE 以降では、Craig Peterson の回答を使用します(冗長な 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;
于 2012-01-05T08:35:55.697 に答える
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; 

または、各アクションに適切なセッターを記述します。

編集:

その時に必要なのは

  1. 3 つのカスタム アクションを事前定義StdActns.pasされたアクションとして実装します (サンプルについては、を参照してください)。

  2. を呼び出して登録しますActnList.RegisterActions。( RAD Studio のドキュメントを参照してください)

  3. フォームに a を追加したり、すべての TControl の子孫のアクション リスト エディタで事前定義されたアクションのリストに表示できるようにしTActionListたりします。TActionManagerPredefined Actions

トピックについてグーグルで広範な検索を行い、具体的な例を見つけることができます。

于 2011-12-31T08:21:58.487 に答える