如何使用GridPanel创建与RowSpan、ColSpan Delphi类似的组件属性

如何使用GridPanel创建与RowSpan、ColSpan Delphi类似的组件属性,delphi,delphi-xe2,gridpanel,Delphi,Delphi Xe2,Gridpanel,我正在创建一个从gridpanel继承的组件。当我在gridpanel上添加标签、编辑或其他组件时,编辑、标签。。。组件显示在行、列、行范围和列范围属性中。如何创建与这些Row、Col、RowSpan和ColSpan属性相等的新属性。哪一项仅启用何时在gridPanel上创建组件?如果要创建新属性,并且该属性将显示在gridpanel上的“编辑”、“标签”和其他属性中,则为“否” 我正在使用Delphi XE2,这似乎是不可能的。当然,您可以复制源代码并对其进行修改,但不能直接继承 问题是,您可

我正在创建一个从gridpanel继承的组件。当我在gridpanel上添加标签、编辑或其他组件时,编辑、标签。。。组件显示在行、列、行范围和列范围属性中。如何创建与这些Row、Col、RowSpan和ColSpan属性相等的新属性。哪一项仅启用何时在gridPanel上创建组件?如果要创建新属性,并且该属性将显示在gridpanel上的“编辑”、“标签”和其他属性中,则为“否”


我正在使用Delphi XE2,这似乎是不可能的。当然,您可以复制源代码并对其进行修改,但不能直接继承

问题是,您可以从
TControlItem
类继承并添加所需的属性,但不能修改
TControlCollection
ItemClass:
TControlCollection
构造函数替换祖先(
TOwnedCollection
)构造函数,因此无法更改默认ItemClass(
t控制项
)与派生项


您可以尝试使用
TControlItem
的类帮助器,但在这种情况下,您将只有运行时支持(对象检查器和RTTI对此一无所知)。好吧,使用一些讨厌的技巧,您可以做任何您想做的事,但我认为这超出了我们的范围(有关详细信息,请参阅已接受的答案,并阅读引用的艾伦·鲍尔·阿特西科尔的原文)。

遵循代码,在NGridPanel组件中添加新的fake属性

类假属性

unit UPropertyFakeVerticalAlignment;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.Dialogs, DesignIntf,
  DesignEditors, DesignMenus, TypInfo, Winapi.Messages,
  Winapi.Windows, Vcl.StdCtrls, Vcl.Forms, System.Types;

type
  TBaseComponentPropertyEditor = class(TBasePropertyEditor)
  private
    FComponent: TComponent;
    FDesigner: IDesigner;
  protected

  public
    constructor Create(const ADesigner: IDesigner; APropCount: Integer); override;
    property Component: TComponent read FComponent write FComponent;
    property Designer: IDesigner read FDesigner;
  end;

  TPropertyVerticalAlignment = class(TBaseComponentPropertyEditor, IProperty,
      IPropertyKind)
  private
    function GetControl: TControl;
    procedure SetControl(const Value: TControl);
    procedure Activate;
    function AllEqual: Boolean;
    function AutoFill: Boolean;
    procedure Edit; overload;
    function HasInstance(Instance: TPersistent): Boolean;
    function GetEditLimit: Integer;
    procedure GetProperties(Proc: TGetPropProc);
    function GetPropInfo: PPropInfo; virtual;
    function GetPropType: PTypeInfo; virtual;
    procedure Revert;
    function ValueAvailable: Boolean;

  protected
    function GetEditValue(out Value: String): Boolean;
    function GetKind: TTypeKind;
    function GetName: string; reintroduce;
    function GetValue: string; reintroduce;
    procedure SetValue(const Value: String); reintroduce;
    function GetAttributes: TPropertyAttributes;
    procedure GetValues(Proc: TGetStrProc);
  public
    property Control: TControl read GetControl write SetControl;
  end;

  type
    TAddPropertyFakeVerticalAlignment = class(TSelectionEditor, ISelectionPropertyFilter)
      procedure FilterProperties(const ASelection: IDesignerSelections; const
        ASelectionProperties: IInterfaceList);
  end;


implementation

uses NGridPanel;

procedure TAddPropertyFakeVerticalAlignment.FilterProperties(const ASelection:
    IDesignerSelections; const ASelectionProperties: IInterfaceList);
var
  ParentProperty: TPropertyVerticalAlignment;
begin
  if aSelection.Count <> 1 then
   Exit;
  if (aSelection[0] is TControl) then
  begin
    if TControl(ASelection[0]).GetParentComponent is TNGridPanel then
    begin
      ParentProperty := TPropertyVerticalAlignment.Create(inherited Designer, 1);
      ParentProperty.Control := TControl(ASelection[0]);
      ASelectionProperties.Add(ParentProperty as IProperty);
    end;
  end;
end;

constructor TBaseComponentPropertyEditor.Create(const ADesigner: IDesigner;
  APropCount: Integer);
begin
  inherited Create(ADesigner, APropCount);
  FDesigner := ADesigner;
end;

{ TPropertyVerticalAlignment }

procedure TPropertyVerticalAlignment.Activate;
begin

end;

function TPropertyVerticalAlignment.AllEqual: Boolean;
begin
  Result := True;
end;

function TPropertyVerticalAlignment.AutoFill: Boolean;
begin
  Result := True;
end;

procedure TPropertyVerticalAlignment.Edit;
begin
  inherited;
end;

function TPropertyVerticalAlignment.GetAttributes: TPropertyAttributes;
begin
  Result := [paValueList, paAutoUpdate, paRevertable, paValueEditable];
end;

function TPropertyVerticalAlignment.GetControl: TControl;
begin
  Result := TControl(Component);
end;

function TPropertyVerticalAlignment.GetEditLimit: Integer;
begin
  Result := -1;
end;

function TPropertyVerticalAlignment.GetEditValue(out Value: string): Boolean;
begin
  if Value = EmptyStr then
   Value := GetValue();
  Result := True;
end;

function TPropertyVerticalAlignment.GetKind: TTypeKind;
begin
  Result := tkClass;
end;

function TPropertyVerticalAlignment.GetName: string;
begin
  Result := 'VerticalAlignment';
end;

procedure TPropertyVerticalAlignment.GetProperties(Proc: TGetPropProc);
begin
  inherited;

end;

function TPropertyVerticalAlignment.GetPropInfo: PPropInfo;
begin
  Result := nil;
end;

function TPropertyVerticalAlignment.GetPropType: PTypeInfo;
begin
  Result := nil;
end;

function TPropertyVerticalAlignment.GetValue: string;
var
  AGridPanel: TNGridPanel;
  AControlItem: TControlItemFreedom;
  AIndex: Integer;
begin
  if Assigned(Control) and Assigned(Control.Parent) then
  begin
    if Control.GetParentComponent is TNGridPanel then
    begin
      AGridPanel := TNGridPanel(Control.Parent);

      if AGridPanel <> nil then
      begin
        AIndex := AGridPanel.ControlCollectionFreedom.IndexOf(Control);
        if AIndex > -1 then
        begin
          AControlItem := AGridPanel.ControlCollectionFreedom.Items[AIndex];
          Result := GetEnumName(TypeInfo(TVerticalAlignment), Integer(AControlItem.VerticalAlignment));
        end;
      end;
    end;
  end
  else
    Result := 'taAlignTop';
end;


procedure TPropertyVerticalAlignment.GetValues(Proc: TGetStrProc);
begin
  Designer.GetComponentNames(GetTypeData(TypeInfo(TVerticalAlignment)), Proc);
  if Assigned(Control) and Assigned(Control) then
  begin
    Proc(GetEnumName(TypeInfo(TVerticalAlignment), 0));
    Proc(GetEnumName(TypeInfo(TVerticalAlignment), 1));
    Proc(GetEnumName(TypeInfo(TVerticalAlignment), 2));
  end;
end;

function TPropertyVerticalAlignment.HasInstance(Instance: TPersistent): Boolean;
begin
  Result := True;
end;

procedure TPropertyVerticalAlignment.Revert;
begin

end;

procedure TPropertyVerticalAlignment.SetControl(const Value: TControl);
begin
  Component := Value;
end;

procedure TPropertyVerticalAlignment.SetValue(const Value: String);
var
  P: TWinControl;
  AGridPanel: TNGridPanel;
  AControlItem: TControlItemFreedom;
  AIndex: Integer;
  AVerticalAlignment: TVerticalAlignment;
begin
 inherited;
  if Assigned(Control) and Assigned(Control.Owner) then
  begin
    if Control.GetParentComponent is TNGridPanel then
    begin
      AGridPanel := TNGridPanel(Control.Parent);

      if AGridPanel <> nil then
      begin
        AIndex := AGridPanel.ControlCollectionFreedom.IndexOf(Control);
        if AIndex > -1 then
        begin
          AControlItem := AGridPanel.ControlCollectionFreedom.Items[AIndex];

          AIndex := GetEnumValue(TypeInfo(TVerticalAlignment), Value);

          AVerticalAlignment := TVerticalAlignment(AIndex);

          AControlItem.VerticalAlignment := AVerticalAlignment;
          Designer.Modified;
        end;
      end;
    end;
  end;
end;

function TPropertyVerticalAlignment.ValueAvailable: Boolean;
begin
  Result := True;
end;

end.
类组件

unit NGridPanelReg;

interface

uses
  System.Classes, Vcl.Controls, DesignIntf, DesignEditors, TypInfo,
  Winapi.Messages,
  Winapi.Windows, Vcl.StdCtrls, Vcl.Forms, System.Types;

  procedure Register;

implementation

uses NGridPanel, UPropertyFakeVerticalAlignment;


procedure Register;
begin
  RegisterComponents('EMSI', [TNGridPanel]);
  RegisterSelectionEditor(TControl, TAddPropertyFakeVerticalAlignment);
  UnlistPublishedProperty(TNGridPanel, 'ControlCollectionFreedom');
end;
unit NGridPanel;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.Dialogs, Variants,
  TypInfo, Winapi.Messages, Winapi.Windows, Vcl.StdCtrls, Vcl.Forms, System.Types;

type

  TControlItemFreedom = class(TCollectionItem)
  private
    FControl: TControl;
    FVerticalAlignment: TVerticalAlignment;
    procedure SetControl(Value: TControl);
    function GetGridPanel: TCustomGridPanel;
    procedure SetVerticalAlignment(const Value: TVerticalAlignment);
  protected
    procedure AssignTo(Dest: TPersistent); override;
    property GridPanel: TCustomGridPanel read GetGridPanel;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property VerticalAlignment: TVerticalAlignment read FVerticalAlignment write SetVerticalAlignment;
    property Control: TControl read FControl write SetControl;
  end;

  TControlCollectionFreedom = class(TOwnedCollection)
  private
    function GetItem(Index: Integer): TControlItemFreedom;
    procedure SetItem(Index: Integer; const Value: TControlItemFreedom);
  protected

  public
    function IndexOf(AControl: TControl): Integer;
    constructor Create(AOwner: TPersistent);
    function Add: TControlItemFreedom;
    procedure AddControl(AControl: TControl; AVerticalAlignment: TVerticalAlignment);
    procedure RemoveControl(AControl: TControl);
    property Items[Index: Integer]: TControlItemFreedom read GetItem write SetItem; default;
  end;

  TNGridPanel = class(TGridPanel)
  private
    FControlCollectionFreedom: TControlCollectionFreedom;
    procedure SetControlCollectionVertical(const Value: TControlCollectionFreedom);
    procedure CMControlChange(var Message: TCMControlChange); message CM_CONTROLCHANGE;
  protected
    procedure Loaded; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property ControlCollectionFreedom: TControlCollectionFreedom read FControlCollectionFreedom write SetControlCollectionVertical;
  end;

implementation


procedure TNGridPanel.CMControlChange(var Message: TCMControlChange);
begin
  inherited;
  if not (csLoading in ComponentState) then
    if Message.Inserting and (Message.Control.Parent = Self) then
    begin
      DisableAlign;
      try
        Message.Control.Anchors := [];
        FControlCollectionFreedom.AddControl(Message.Control, 'taCenter', taAlignTop, True);
      finally
        EnableAlign;
      end;
    end else
      FControlCollectionFreedom.RemoveControl(Message.Control);
end;

constructor TNGridPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FControlCollectionFreedom := TControlCollectionFreedom.Create(Self);
end;


destructor TNGridPanel.Destroy;
begin
  inherited;
  FreeAndNil(FControlCollectionFreedom);
end;

procedure TNGridPanel.Loaded;
begin
  inherited;
end;

procedure TNGridPanel.SetControlCollectionVertical(const Value: TControlCollectionFreedom);
begin
  FControlCollectionFreedom := Value;
end;

{ TControlItemVertical }

procedure TControlItemFreedom.AssignTo(Dest: TPersistent);
begin
  inherited;
  if Dest is TControlItemFreedom then
  begin
    with TControlItem(Dest) do
    begin
      FControl := Self.Control;
      FVerticalAlignment := Self.VerticalAlignment;
      Changed(False);
    end;
  end;
end;

constructor TControlItemFreedom.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FVerticalAlignment := taAlignTop;
end;

destructor TControlItemFreedom.Destroy;
begin

  inherited;
end;

function TControlItemFreedom.GetGridPanel: TCustomGridPanel;
var
  Owner: TControlCollection;
begin
  Owner := TControlCollection(GetOwner);
  if Owner <> nil then
    Result := Owner.Owner
  else
    Result := nil;
end;

procedure TControlItemFreedom.SetControl(Value: TControl);
begin
  if FControl <> Value then
  begin
{$IF DEFINED(CLR)}
    if Assigned(Value) and Value.Equals(GridPanel) then
{$ELSE}
    if Value = GridPanel then
{$IFEND}
      raise EGridPanelException.Create('Controle Inválido');
    FControl := Value;
    Changed(False);
  end;
end;

procedure TControlItemFreedom.SetVerticalAlignment(
  const Value: TVerticalAlignment);
begin
  FVerticalAlignment := Value;
end;

{ TControlCollectionVertical }

function TControlCollectionFreedom.Add: TControlItemFreedom;
begin
  Result := TControlItemFreedom(inherited Add);
end;

procedure TControlCollectionFreedom.AddControl(AControl: TControl; AVerticalAlignment: TVerticalAlignment);
  procedure PlaceInCell(ControlItem: TControlItemFreedom;  AVerticalAlignment: TVerticalAlignment);
  var
    I, J: Integer;
  begin
    with ControlItem do
    try
      Control := AControl;
      VerticalAlignment := AVerticalAlignment;
    except
      Control := nil;
      Free;
      raise;
    end;
  end;
begin
   if IndexOf(AControl) < 0 then
   begin
     PlaceInCell(Add, AVerticalAlignment);
   end;
end;

function TControlCollectionFreedom.IndexOf(AControl: TControl): Integer;
begin
  for Result := 0 to Count - 1 do
    if TControlItemFreedom(Items[Result]).Control = AControl then
      Exit;
  Result := -1;
end;

procedure TControlCollectionFreedom.RemoveControl(AControl: TControl);
var
  I: Integer;
begin
  for I := Count - 1 downto 0 do
    if Items[I].Control = AControl then
    begin
      Items[I].Control := nil;
      Delete(I);
      Exit;
    end;
end;

procedure TControlCollectionFreedom.SetItem(Index: Integer;
  const Value: TControlItemFreedom);
begin
  inherited SetItem(Index, Value);
end;

constructor TControlCollectionFreedom.Create(AOwner: TPersistent);
begin
  inherited Create(AOwner, TControlItemFreedom);
end;

function TControlCollectionFreedom.GetItem(Index: Integer): TControlItemFreedom;
begin
  Result := TControlItemFreedom(inherited GetItem(Index));
end;

end.
单元面板;
接口
使用
System.SysUtils、System.Class、Vcl.Controls、Vcl.ExtCtrls、Vcl.Dialogs、Variant、,
TypInfo、Winapi.Messages、Winapi.Windows、Vcl.StdCtrls、Vcl.Forms、System.type;
类型
TControlItemFreedom=类(TCollectionItem)
私有的
f控制:t控制;
垂直对齐:垂直对齐;
程序设置控制(值:t控制);
函数GetGridPanel:TCustomGridPanel;
程序SetVerticalAlignment(常量值:TVerticalAlignment);
受保护的
程序赋值(Dest:TPersistent);重写;
属性GridPanel:TCustomGridPanel读取GetGridPanel;
公众的
构造函数创建(集合:TCollection);重写;
析构函数销毁;重写;
出版
属性垂直对齐:TVerticalAlignment读取FVerticalAlignment写入SetVerticalAlignment;
属性控制:t控制读FControl写SetControl;
结束;
TControlCollectionFreedom=类(TOwnedCollection)
私有的
函数GetItem(索引:整数):TControlItemFreedom;
过程SetItem(索引:整数;常量值:TControlItemFreedom);
受保护的
公众的
函数IndexOf(AControl:TControl):整数;
构造函数创建(AOwner:TPersistent);
功能新增:TControlItemFreedom;
程序添加控制(A控制:t控制;避免对齐:t垂直对齐);
程序删除控制(A控制:T控制);
属性项[索引:整数]:TControlItemFreedom read GetItem write SetItem;默认值;
结束;
TNGridPanel=class(TGridPanel)
私有的
FControlCollectionFreedom:TControlCollectionFreedom;
过程SetControlCollectionVertical(常量值:TControlCollectionFreedom);
程序CMControlChange(var消息:TCMControlChange);消息CM\U CONTROLCHANGE;
受保护的
程序加载;覆盖;
公众的
构造函数创建(AOOwner:TComponent);重写;
析构函数销毁;重写;
出版
属性ControlCollectionFreedom:TControlCollectionFreedom读取FControlCollectionFreedom写入SetControlCollectionVertical;
结束;
实施
过程TNGridPanel.CMControlChange(变量消息:TCMControlChange);
开始
继承;
如果不是(组件状态下的csLoading),则
如果Message.Inserting和(Message.Control.Parent=Self),则
开始
不结盟;
尝试
Message.Control.Anchors:=[];
FControlCollectionFreedom.AddControl(Message.Control,'taCenter',taAlignTop,True);
最后
使能林;
结束;
结束其他
FControlCollectionFreedom.RemoveControl(Message.Control);
结束;
构造函数TNGridPanel.Create(AOwner:TComponent);
开始
继承的创建(AOOwner);
FControlCollectionFreedom:=TControlCollectionFreedom.Create(Self);
结束;
销毁程序TNGridPanel.Destroy;
开始
继承;
FreeAndNil(FControlCollectionFreedom);
结束;
程序面板。已加载;
开始
继承;
结束;
过程TNGridPanel.SetControlCollectionVertical(常量值:TControlCollectionFreedom);
开始
FControlCollectionFreedom:=值;
结束;
{TControlItemVertical}
程序TControlItemFreedom.AssignTo(目标:TPersistent);
开始
继承;
如果Dest是TControlItemFreedom,则
开始
使用TControlItem(Dest)do
开始
F控制:=自我控制;
垂直对齐:=自垂直对齐;
更改(假);
结束;
结束;
结束;
构造函数TControlItemFreedom.Create(集合:TCollection);
开始
继承创建(集合);
FVerticalAlignment:=taAlignTop;
结束;
析构函数TControlItemFreedom.Destroy;
开始
继承;
结束;
函数TControlItemFreedom.GetGridPanel:TCustomGridPanel;
变量
所有者:TControlCollection;
开始
所有者:=TControlCollection(GetOwner);
如果所有者为零,则
结果:=所有者。所有者
其他的
结果:=无;
结束;
过程TControlItemFreedom.SetControl(值:TControl);
开始
如果是FControl值,则
开始
{$IF-DEFINED(CLR)}
如果赋值(Value)和Value.Equals(GridPanel),则
{$ELSE}
如果Value=GridPanel,则
{$IFEND}
提出EGridPanelException.Create('Controle Inválido');
FControl:=值;
更改(假);
结束;
结束;
过程TControlItemFreedom.SetVerticalAlignment(
常量值:TVerticalAlignment);
开始
FVerticalAlignment:=值;
结束;
{TControlCollectionVertical}
函数TControlCollectionFreedom.Add:TControlItemFreedom;
开始
结果:=TControlItemFreedom(继承的添加);
结束;