Как улучшить использование кадров Delphi
-
02-10-2019 - |
Вопрос
Я использовал рамы в Delphi в течение многих лет, и они являются одной из самых мощных особенностей VCL, но стандартное использование их, похоже, имеет такой риск, такой как:
Легко случайно перемещать или редактировать рамку подсомысел на форме кадра, не осознавая, что вы «настраиваете» с рамкой - я знаю, что это не влияет на оригинальный код кадра, но это вообще не то, что вы хотели бы.
При работе с рамкой вы все еще подвергаетесь воздействию его подкомпонентов для визуального редактирования, даже когда этот кадр лет и не должен быть затронут.
Поэтому я должен думать ....
Есть ли способ «группировать» компоненты, так что их позиции «заблокированы»? Это было бы полезно для готовых форм, а также кадров. Часто другие разработчики возвращают код для меня, где изменились только границы формы, и даже они не намерены никаких изменений.
Есть ли способ повернуть кадр и его компоненты в один компонент Delphi? Если это так, внутренние органы рамы будут полностью скрыты, и его использование будет увеличиваться дальше.
Я заинтересован в любых мыслях ...
Брайан.
Решение
Регистрация кадров в качестве компонента решает как 1. и 2.:
- Компоненты на раме блокируются, когда вы помещаете этот элемент управления кадром на форме или другом кадре
- Вы получите компонент (на самом деле: Control), который вы можете создать визуально
Но: есть несколько ловков (которые могут быть решены, см. Статью ссылки), из которых наиболее важным является эта:
Когда вы помещаете компоненты на свой кадр, а позже отбросьте этот кадр в качестве компонента на форме или кадре Delphi, компоненты видны на панели структуры.
Проблема в том, что потому, что они видны на панели структуры, вы можете удалить их, вызывая нарушения доступа.
Трюк, чтобы решить это не забыть «SPRIG».
Я узнал этот ценный урок от Рэй Конопка в течение Дельфилистика 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;
Надеюсь это поможет.
- jereen.
Другие советы
Да, просто зарегистрируйте их в качестве компонентов. :-)
Обычно спроектируйте свой кадр и после этого зарегистрируйтесь. Также убедитесь, что не имеют нежелательных зависимостей на разных единицах, поскольку они связаны, когда используется ваш «компонент». Также вы можете добавить 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;
Составьте вышеупомянутое в пакете по вашему выбору, установите его и установите его палитру компонентов. :-)
Емкость
Только для увеличения вклада, обратите внимание, что если вы перейдете к Structure
Окно и щелкните правой кнопкой мыши на имя TFrame, которое вы выбрали, и нажмите на Add to Palete
Опция меню. Это сделает компонент из вашего кадра, и вам не нужно создавать какие-либо Register
процедура. ;-)
Я почти всегда создаю экземпляры кадров в коде. Это легко и хорошо сработало для меня до сих пор.
Я также столкнулся с этой проблемой при попытке использования кадров в качестве компонентов. Существуют различные возможности для устранения очевидных вопросов, но все они подрывают принцип скрытия информации (все подкомпоненты кадра выставляются в качестве опубликованных свойств, что означает, что каждый может получить доступ к ним).
Я решил его, реализуя универсальный компонент «Рамка управления»:
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;
...
При использовании этого подхода пользователь вашего компонента не увидит ваши подкомпоненты.