26

私は何年も Delphi でフレームを使用してきました。フレームは VCL の最も強力な機能の 1 つですが、標準的な使用には次のようなリスクがあるようです。

  1. フレームを「微調整」していることに気づかずに、フレームのホスト フォーム上のフレーム サブコンポーネントを誤って移動または編集するのは簡単です。これが元のフレーム コードに影響を与えないことはわかっていますが、一般的にはあなたが望むものではありません。

  2. フレームで作業しているときは、そのフレームが古くて触れてはならない場合でも、視覚的な編集のためにそのサブコンポーネントにまださらされています。

そこで私は考えるようになりました....

  1. コンポーネントの位置が「ロック」されるようにコンポーネントを「グループ化」する方法はありますか? これは、フレームだけでなく、完成したフォームにも役立ちます。多くの場合、他の開発者は、フォームの境界のみが変更され、変更を意図していないコードを私に返します。

  2. フレームとそのコンポーネントを単一の Delphi コンポーネントに変換する方法はありますか? もしそうなら、フレームの内部は完全に隠され、その使いやすさはさらに向上します.

私はどんな考えにも興味があります...

ブライアン。

4

5 に答える 5

24

フレームをコンポーネントとして登録すると、1. と 2. の両方が解決されます。

  1. そのフレーム コントロールをフォームまたは他のフレームに配置すると、フレーム上のコンポーネントがロックされます。
  2. 視覚的に設計できるコンポーネント(実際にはコントロール)を取得します

ただし、いくつかの問題があります (解決可能です。記事のリンクを参照してください)。その中で最も重要なのは次のようなものです。

コンポーネントをフレームに配置し、後でそのフレームをコンポーネントとして Delphi フォームまたはフレームにドロップすると、コンポーネントが構造ペインに表示されます。

問題は、構造ペインに表示されているため、それらを削除でき、アクセス違反が発生することです。

これを解決するコツは「小枝」を忘れないことです。DelphiLive 2009でレイ コノプカ
から貴重な教訓を学びました

このレッスンは非常に価値があるので、詳しく説明するブログ記事を書きました。

重要な部分は、次の小さなコードです (詳細はブログ投稿を参照)。

procedure RegisterFramesAsComponents(const Page: string; const FrameClasses: array of TFrameClass);
var
  FrameClass: TFrameClass;
begin
  for FrameClass in FrameClasses do
  begin
    RegisterComponents(Page, [FrameClass]);
    RegisterSprigType(FrameClass, TComponentSprig);
  end;
end;

お役に立てれば。

--jeroen

于 2010-04-29T10:27:24.227 に答える
19

はい、コンポーネントとして登録するだけです。:-)

フレームを通常どおりに設計し、この後に登録します。また、「コンポーネント」が使用されるときにこれらがリンクされるため、異なるユニットに不要な依存関係を持たないようにしてください。publishedまた、後でオブジェクト インスペクターで使用するために、プロパティを追加することもできます。たとえば、IDE によって生成された次のコードを参照してください (私のコメントも参照してください)。

unit myUnit;

uses
 ...

type
  TmyComp = class(TFrame) //set your frame name to be the name your component 
    ToolBar1: TToolBar; //different components added in the form designer
    aliMain: TActionList;
    ...
  published //this section is added by hand
    property DataSource: TDataSource read FDataSource write SetDataSource; //some published properties added just for exemplification
    property DefFields: string read FDefFields write SetDefFields;
    ...
  end;


procedure Register; //added by hand

implementation

{$R *.DFM}

procedure Register;
begin
  RegisterComponents('MyFrames', [TmyComp]); //register the frame in the desired component category
end;

選択したパッケージで上記をコンパイルし、インストールして、コンポーネント パレットを確認します。:-)

HTH

于 2010-04-29T08:28:27.240 に答える
8

貢献を増やすためだけに、Structureウィンドウに移動して、選択した TFrame 名を右クリックし、Add to Paleteメニュー オプションをクリックすることに注意してください。Registerこれにより、フレームからコンポーネントが作成され、手順を作成する必要はありません。;-)

于 2012-07-04T03:01:43.907 に答える
7

ほとんどの場合、コードでフレームインスタンスを作成しています。これは簡単で、これまでのところうまく機能しました。

于 2010-04-29T08:21:58.923 に答える
4

フレームをコンポーネントとして使用しようとしたときにも、その問題に遭遇しました。明らかな問題を解決するためのさまざまな可能性がありますが、それらはすべて、情報隠蔽の原則を弱体化させます (フレームのすべてのサブコンポーネントは、公開されたプロパティとして公開されます。つまり、誰もがそれらにアクセスできます)。

一般的な「フレーム コントロール」コンポーネントを実装することで解決しました。

unit RttiBrow.Cbde.FrameControl;

interface

uses
  Classes, Controls, Forms, Messages, ExtCtrls;

type
  TFrameClass = class of TFrame;

  TComponentFrame = class (TFrame)
  private
    function GetClientHeight: Integer;
    function GetClientWidth: Integer;
    procedure SetClientHeight(const Value: Integer);
    procedure SetClientWidth(const Value: Integer);
    function GetOldCreateOrder: Boolean;
    procedure SetOldCreateOrder(const Value: Boolean);
    function GetPixelsPerInch: Integer;
    procedure SetPixelsPerInch(const Value: Integer);
    function GetTextHeight: Integer;
    procedure SetTextHeight(const Value: Integer);
  published
    { workarounds for IDE bug }
    property ClientWidth: Integer read GetClientWidth write SetClientWidth stored False;
    property ClientHeight: Integer read GetClientHeight write SetClientHeight stored False;
    property OldCreateOrder: Boolean read GetOldCreateOrder write SetOldCreateOrder stored False;
    property PixelsPerInch: Integer read GetPixelsPerInch write SetPixelsPerInch stored False;
    property TextHeight: Integer read GetTextHeight write SetTextHeight stored False;
  end;

  TComponentFrame<TFrameControl: class { TControl }> = class (TComponentFrame)
  private
    function GetController: TFrameControl; inline;
  protected
    property Controller: TFrameControl read GetController;
  public
    constructor Create (AOwner: TComponent); override;
  end;

  TFrameControl<T: TFrame> = class (TWinControl)
  private
    FFrame: T;
    function PlainFrame: TFrame;
  protected
    procedure CreateParams (var Params: TCreateParams); override;
    property Frame: T read FFrame;
  public
    constructor Create (AOwner: TComponent); override;
    property DockManager;
  published
    property Align;
    property Anchors;
    property BiDiMode;
    property Color;
    property Constraints;
    property Ctl3D;
    property UseDockManager default True;
    property DockSite;
    property DoubleBuffered;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property Font;
    property ParentBiDiMode;
    property ParentBackground;
    property ParentColor;
    property ParentCtl3D;
    property ParentDoubleBuffered;
    property ParentFont;
    property ParentShowHint;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Touch;
    property Visible;
    property OnAlignInsertBefore;
    property OnAlignPosition;
    property OnCanResize;
    property OnConstrainedResize;
    property OnDockDrop;
    property OnDockOver;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnGesture;
    property OnGetSiteInfo;
    property OnMouseActivate;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnStartDock;
    property OnStartDrag;
    property OnUnDock;
  end;


implementation

uses
  Windows;

{ TFrameControl<T> }

constructor TFrameControl<T>.Create(AOwner: TComponent);
begin
  inherited;
  FFrame := T (TFrameClass (T).Create (Self));
  PlainFrame.Parent := Self;
  PlainFrame.Align := alClient;
end;

procedure TFrameControl<T>.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := Params.Style or WS_CLIPCHILDREN;
  Params.ExStyle := Params.ExStyle or WS_EX_CONTROLPARENT;
end;

function TFrameControl<T>.PlainFrame: TFrame;
begin
  Result := FFrame; // buggy compiler workaround
end;


{ TComponentFrame }

function TComponentFrame.GetOldCreateOrder: Boolean;
begin
  Result := False;
end;

function TComponentFrame.GetPixelsPerInch: Integer;
begin
  Result := 0;
end;

function TComponentFrame.GetTextHeight: Integer;
begin
  Result := 0;
end;

procedure TComponentFrame.SetClientHeight(const Value: Integer);
begin
  Height := Value;
end;

procedure TComponentFrame.SetClientWidth(const Value: Integer);
begin
  Width := Value;
end;

procedure TComponentFrame.SetOldCreateOrder(const Value: Boolean);
begin
end;

procedure TComponentFrame.SetPixelsPerInch(const Value: Integer);
begin
end;

procedure TComponentFrame.SetTextHeight(const Value: Integer);
begin
end;

function TComponentFrame.GetClientHeight: Integer;
begin
  Result := Height;
end;

function TComponentFrame.GetClientWidth: Integer;
begin
  Result := Width;
end;


{ TComponentFrame<TFrameControl> }

constructor TComponentFrame<TFrameControl>.Create(AOwner: TComponent);
begin
  inherited;
  Assert (AOwner <> nil);
  Assert (AOwner.InheritsFrom (TFrameControl));
end;

function TComponentFrame<TFrameControl>.GetController: TFrameControl;
begin
  Result := TFrameControl (Owner);
end;


end.

このクラスでは、コンポーネントとしてのフレームの追加は 2 段階のプロセスになります。

  // frame unit
type
  TFilteredList = class;

  TFrmFilteredList = class (TComponentFrame<TFilteredList>)
    // lots of published sub-components and event methods like this one:
    procedure BtnFooClick(Sender: TObject);
  end;

  TFilteredList = class (TFrameControl<TFrmFilteredList>)
  private
    procedure Foo;
  public
    // the component's public interface
  published
    // the component's published properties
  end;

procedure Register;
...
procedure Register;
begin
  RegisterComponents ('CBDE Components', [TFilteredList]);
end;

procedure TFrmFilteredList.BtnFooClick(Sender: TObject);
begin
  Controller.Foo;
end;

procedure TFilteredList.Foo;
begin
end;
...

このアプローチを使用すると、コンポーネントのユーザーにはサブコンポーネントが表示されません。

于 2010-04-29T13:05:18.293 に答える