我在Delphi中使用了多年的框架,它们是VCL最强大的功能之一,但是它们的标准使用似乎有一些风险,例如:
很容易意外地移动或编辑框架主机窗体上的框架子组件,而没有意识到你正在“调整”框架 - 我知道这不会影响原始框架代码,但通常不会你想要什么。
使用框架时,您仍然可以使用其子组件进行可视化编辑,即使该框架已有数年之久且不应触及。
所以我开始思考......
是否有一种“分组”组件的方式,使其位置“锁定”?这对完成的表格和框架都很有用。通常其他开发人员将代码返回给我,其中只有表单边界发生了变化,甚至他们也不打算进行任何更改。
有没有办法将框架及其组件转换为单个Delphi组件?如果是这样,框架内部将完全隐藏,其可用性将进一步增加。
我对任何想法感兴趣......
布赖恩。
答案 0 :(得分:22)
将帧注册为组件可以解决1.和2:
但是:有一些捕获(可以解决,见文章链接),其中最重要的是这一个:
当您在框架上放置组件,然后将该框架作为组件放在Delphi表单或框架上时,组件在结构窗格中可见。
问题是因为它们在结构窗格中可见,您可以删除它们,从而导致访问冲突。
解决这个问题的诀窍not forget the 'sprig' 我在Ray Konopka 2009年期间从DelphiLive学到了宝贵的教训。
由于课程非常有价值,我在其上写了blog post,详细描述了它。
关键部分是这一小段代码(博客文章中有更多细节):
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
答案 1 :(得分:17)
是的,只需将它们注册为组件即可。 : - )
正常设计您的框架,然后注册它。另外,请确保不要对不同的单元有不必要的依赖关系,因为在使用“组件”时这些依赖关系。您还可以添加published
属性,以便稍后在Object Inspector中使用它们。例如,请参阅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
答案 2 :(得分:8)
只是为了增加贡献,请注意,如果您转到Structure
窗口并右键单击您选择的TFrame名称,然后单击Add to Palete
菜单选项。
这将使您的Frame中的组件成为一个组件,您不需要创建任何Register
过程。 ; - )
答案 3 :(得分:5)
我几乎总是在代码中创建框架实例。到目前为止,这对我来说很容易并且运作良好。
答案 4 :(得分: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.
使用此类,将帧添加为组件将变为两个阶段的过程:
// 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;
...
使用此方法时,组件的用户将看不到您的子组件。