delphi 自带的stringgrid在设计期,给第一行各列添加一个表头。
经过实验, 从Tstringgrid派生一个类,TMystrgrid, 增加一个collection属性,FLISTPROPS,
tlistprops从TCOLLECTION继承,添加一个FOWNER字段,如下
type
TListProps = class; // 这个类是用于表示该List属性的集合类型
TMyStrGrid = class(TStringGrid)
private
FRowHeaders: TStringList;
FListProps: TListProps;
procedure SetListProps(const Value: TListProps);
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: Tcomponent); override;
destructor Destroy; override;
published
{ Published declarations }
property ListProps: TListProps read FListProps write SetListProps;
// List属性集合表示每列的表头字段
end;
TListItem = class(TCollectionItem)
private
FCaption: string;
procedure SetCaption(const Value: string);
protected
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure Assign(source: TPersistent); override;
// 因为需要进行赋值操作,必须重载该方法,将数据域进行copy
published
property Caption: string read FCaption write SetCaption;
end;
TListProps = class(TCollection)
private
// fowner这个属性是必须的,因为对于List属性,
// 如果在设计时在弹出的窗口中进行了编辑,必须将修改的结果反应到原始控件中,
// 这里通过这个属性表明了List属性的所有者(Owner),
// 这样在List属性被修改时可以通知Owner作出相应调整,
// 与之相应的,一般在这个类里还需要重载:
// procedure Update(Item: TCollectionItem); override;这个方法
FOwner: TMyStrGrid;
function GetItem(Index: Integer): TListItem;
procedure SetItem(Index: Integer; const Value: TListItem);
protected
function GetOwner: TPersistent; override;
procedure Update(Item: TCollectionItem); override;
public
constructor Create(AOwner: TMyStrGrid);
function Add: TListItem;
// procedure Delete(Index: Integer);
property Items[Index: Integer]: TListItem read GetItem
write SetItem; default;
published
end;
经过多次尝试,终于知道在集合项的值CAPTION改变时setcaption方法中需要通知集合类listprops更新update.
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TMyStrGrid]);
end;
{ TMyStrGrid }
constructor TMyStrGrid.Create(AOwner: Tcomponent);
begin
inherited;
self.FListProps := TListProps.Create(self);
end;
destructor TMyStrGrid.Destroy;
begin
FreeAndNil(FListProps);
inherited;
end;
procedure TMyStrGrid.SetListProps(const Value: TListProps);
begin
ListProps.Assign(Value);
end;
{ TListItem }
procedure TListItem.Assign(source: TPersistent);
begin
inherited;
if source is TListItem then
begin
if assigned(Collection) then
Collection.BeginUpdate;
FCaption := TListItem(source).FCaption;
Collection.EndUpdate;
end
else
inherited Assign(source);
end;
constructor TListItem.Create(Collection: TCollection);
begin
inherited Create(Collection);
FCaption := '';
end;
destructor TListItem.Destroy;
begin
inherited Destroy;
end;
procedure TListItem.SetCaption(const Value: string);
begin
Collection.BeginUpdate;
FCaption := Value;
Collection.EndUpdate;
//此处使用beginupdate,endupdate才会自动调用collection的update函数,
//在update重载函数中更新对应的stringgrid的cells内容
end;
{ TListProps }
function TListProps.Add: TListItem;
begin
result := TListItem(inherited Add);
//此处调用collection.beginupdate, endupdate不起作用。
end;
constructor TListProps.Create(AOwner: TMyStrGrid);
begin
inherited Create(TListItem);
FOwner := AOwner;
end;
function TListProps.GetItem(Index: Integer): TListItem;
begin
result := TListItem(inherited Items[Index]);
end;
function TListProps.GetOwner: TPersistent;
begin
result := FOwner;
end;
procedure TListProps.SetItem(Index: Integer; const Value: TListItem);
begin
inherited SetItem(index, Value);
end;
procedure TListProps.Update(Item: TCollectionItem);
var
i: Integer;
begin
if assigned(FOwner) then
begin
for i := 0 to Count - 1 do
if i < FOwner.colcount then
begin
FOwner.Cells[i, 0] := Items[i].FCaption;
end;
end;
//这个过程中还需要考虑如果是删除了集合的item时,如何清除掉cells中多余的值
end;
end.
对于使用TSTRINGLIST表示表格的表头会比较简单,使用另外的思路。
欢迎交流。