Comment améliorer L'utilisation des cadres Delphi

J'ai utilisé des cadres dans Delphi pendant des années, et ils sont l'une des fonctionnalités les plus puissantes de la VCL, mais l'utilisation standard d'entre eux semble avoir un risque tel que:

  1. Il est facile de déplacer ou d'éditer accidentellement les sous-composants du cadre sur le formulaire hôte d'un cadre sans se rendre compte que vous "peaufinez" avec le cadre-je sais que cela n'affecte pas le code du cadre d'origine, mais ce n'est généralement pas ce que vous voulez.

  2. Lorsque vous travaillez avec le cadre, vous êtes toujours exposé à ses sous-Composants pour l'édition visuelle, même lorsque ce cadre est ans et ne doit pas être touché.

Alors j'ai réfléchi....

  1. Existe-t-il un moyen de "regrouper" les composants de sorte que leurs positions soient "verrouillées"? Cela serait utile pour les formes finies ainsi que les cadres. Souvent, d'autres développeurs me renvoient du code où seules les limites du formulaire ont changé et même ils n'avaient pas l'intention de changer.

  2. Y a-t-il un moyen de tourner un cadre et ses composants en un seul composant Delphi? Si c'est le cas, les internes du cadre seraient complètement cachés et sa facilité d'utilisation augmenterait encore.

Je suis intéressé par toutes les pensées...

Brian.

22
demandé sur menjaraz 2010-04-29 11:40:18

5 réponses

L'enregistrement de vos cadres en tant que composant résout les deux 1. et 2.:

  1. Les composants du cadre sont verrouillés lorsque vous placez ce contrôle de cadre sur un formulaire ou un autre cadre
  2. , vous obtiendrez un composant (en fait: contrôle) que vous pouvez concevoir visuellement

Mais: il y a quelques captures (qui peuvent être résolues, voir le lien de l'article), dont le plus important est celui-ci:

Lorsque vous placez des composants sur votre cadre, puis supprimez ce cadre en tant que Delphi form ou frame, les composants sont visibles dans le volet Structure.

Le problème est que parce qu'ils sont visibles dans le volet structure, vous pouvez les supprimer, provoquant des violations d'accès.

L'astuce pour résoudre ce à ne pas oublier le 'branche'.
J'ai appris cette précieuse leçon de Ray Konopka pendantDelphiLive 2009.

Comme la leçon est si précieuse, j'ai écrit un article de blog qui le décrit dans détail.

La partie essentielle est ce petit morceau de code (plus de détails dans le billet de blog):

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;

J'espère que cela aide.

--jeroen

22
répondu Jeroen Wiert Pluimers 2012-12-03 13:28:38

Oui, il suffit de les enregistrer en tant que composants. :-)

Concevez votre cadre normalement et après cela enregistrez-le. Assurez-vous également de ne pas avoir de dépendances indésirables sur différentes unités car celles-ci sont liées lorsque votre 'composant' est utilisé. Vous pouvez également ajouter des propriétés published afin de les utiliser plus tard dans L'Inspecteur D'objets. Voir, par exemple, le code suivant généré par l'IDE (voir aussi mes commentaires):

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;

Compilez ce qui précède dans un paquet de votre choix, installez-le et vérifiez-le palette de composants. :-)

HTH

17
répondu John Thomas 2010-04-29 08:28:27

Juste pour augmenter la contribution, notez que si vous allez à la fenêtre Structure et faites un clic droit sur le nom TFrame que vous avez choisi, et cliquez sur l'option de menu Add to Palete. Cela fera un composant de votre cadre et vous n'avez pas besoin de créer de procédure Register. ;-)

8
répondu PSyLoCKe 2012-07-04 03:01:43

Je crée presque toujours des instances de cadre dans le code. C'est facile et a bien fonctionné pour moi jusqu'à présent.

5
répondu Uli Gerhardt 2010-04-29 08:21:58

J'ai également rencontré ce problème en essayant d'utiliser des cadres comme composants. Il existe différentes possibilités pour résoudre les problèmes évidents, mais elles sapent toutes le principe de la dissimulation de l'information (tous les sous-composants du cadre sont exposés en tant que propriétés publiées, ce qui signifie que tout le monde peut y accéder).

Je l'ai résolu en implémentant un composant Générique "frame control":

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.

Avec cette classe, l'ajout d'une trame en tant que composant devient un processus en deux étapes:

  // 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;
...

Quand en utilisant cette approche, l'utilisateur de votre composant ne verrez pas vos sous-composants.

4
répondu Moritz Beutel 2010-05-21 12:55:46