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