BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[Long] TCollectionItem - reaction for properties changing

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi VCL Components Writing
View previous topic :: View next topic  
Author Message
Wojciech \"Spook\" Sura
Guest





PostPosted: Thu Feb 15, 2007 3:34 am    Post subject: [Long] TCollectionItem - reaction for properties changing Reply with quote



Hi!

I'm writing enhanced grid component, which consists of some other components
(TStringGrid, THeaderControl and TEdits).

The class ownership is:

TSpkGridColumn = class(TCollectionItem)
|
TSpkGridColumns = class(TCollection)
|
TSpkGrid = class(TPanel)

I want the TSpkGrid component to be informed in designtime about any changes
in TSpkGridColumn's - to properly change all internal components.

I've tried:

1. Writing proper events passed from TSpkGridColumn.SetProperty thru
TSpkGridColumns.SpkGridColumnEventHandler to TSpkGrid.EventHandler. That is,
when the property was changed in TSpkGridColumn, it executed the event which
was "cought" by TSpkGridColumns, which then executed event "cought" by
TSpkGrid.

It worked perfectly... in runtime. When I added elements (columns) in IDE,
the events weren't properly assigned though assigned in TSpkGridColumns.add
and TSpkGridColumns.assign.

2. Forcing execution of owner's method, the "back-inheritance", that is:

procedure TSpkGridColumn.SetProperty(AProperty : integer);

begin
FProperty:=AProperty;

(Collection as TSpkGridColumns).EventHandler;
end;

However, I've recieved numerous errors saying "Error reading
TSpkGridColumn.Property: List index out of bounds: 0"

It's very strange, because always before iterating thru Collection items, I
do a check:

if FColumns.count>0 then
for i:=0 to FColumns.count-1 do...

Can someone help?...

I include the source of component below:

<Code>
unit SpkGrid;

interface

uses Classes, StdCtrls, ExtCtrls, ComCtrls, Controls, Grids, SysUtils, Math,
Contnrs, Forms;

type TSpkGrid = class;
TSpkGridColumn = class;
TSpkGridColumns = class;

TSpkGridColumn = class(TCollectionItem)
private
FWidth : integer;
FCaption : string;

protected
procedure SetWidth(AWidth : integer);
procedure SetCaption(ACaption : string);
public
constructor create(Collection: TSpkGridColumns); reintroduce;
destructor destroy; override;
published
property Width : integer read FWidth write SetWidth;
property Caption : string read FCaption write SetCaption;
end;

TSpkGridColumns = class(TCollection)
private
FOwnerGrid : TSpkGrid;
FOnColumnsChanged : TNotifyEvent;
FOnVisualsChanged : TNotifyEvent;
protected
function GetItem(index : integer) : TSpkGridColumn; reintroduce;
procedure SetItem(index : integer; AItem : TSpkGridColumn);
reintroduce;
procedure ColumnVisualsChangedHandler(Sender : TObject);
procedure ColumnChangedHandler(Sender : TObject);
public
function GetOwner : TPersistent; override;
constructor create(AOwnerGrid : TSpkGrid); reintroduce;
destructor destroy; override;
function Add : TSpkGridColumn; reintroduce;
procedure Delete(index : integer);
procedure Assign(Target : TPersistent); override;
procedure Update(item : TCollectionItem); override;
function Insert(Index: Integer): TSpkGridColumn;
property Items[index : integer] : TSpkGridColumn read GetItem write
SetItem;
published
property OnColumnsChanged : TNotifyEvent read FOnColumnsChanged write
FOnColumnsChanged;
property OnVisualsChanged : TNotifyEvent read FOnVisualsChanged write
FOnVisualsChanged;
end;

TEditArray = array of TEdit;

TSpkGrid = class(TPanel)
private
FColumns : TSpkGridColumns;

FOnColumnVisualsChanged : TNotifyEvent;
FOnColumnsChanged : TNotifyEvent;

FGrid : TStringGrid;
FHeaders : THeaderControl;
FEditPanel : TPanel;
FEditList : TEditArray;
protected
procedure ColumnsChangedHandler(Sender : TObject);
procedure ColumnVisualsChangedHandler(Sender : TObject);
procedure TopLeftChangedHandler(Sender : TObject);
procedure SectionResizeHandler(HeaderControl: THeaderControl;
Section: THeaderSection);
procedure SetColumns(Value : TSpkGridColumns);
public
constructor create(AOwner : TComponent); override;
destructor destroy; override;
procedure RebuildColumns;
published
property OnColumnVisualsChanged : TNotifyEvent read
FOnColumnVisualsChanged write FOnColumnVisualsChanged;
property OnColumnsChanged : TNotifyEvent read FOnColumnsChanged write
FOnColumnsChanged;
property Columns : TSpkGridColumns read FColumns write SetColumns;
end;

procedure Register;

implementation

procedure Register;

begin
RegisterComponents('SpookSoft',[TSpkGrid]);
end;

{ TSpkGridColumn }

procedure TSpkGridColumn.SetWidth(AWidth : integer);

begin
FWidth:=AWidth;
end;

procedure TSpkGridColumn.SetCaption(ACaption : string);

begin
FCaption:=ACaption;
end;

constructor TSpkGridColumn.create(Collection: TSpkGridColumns);

begin
inherited create(Collection);
FWidth:=150;
FCaption:='Kolumna';
end;

destructor TSpkGridColumn.destroy;

begin
inherited destroy;
end;

{ TSpkGridColumns }

procedure TSpkGridColumns.SetItem(index : integer; AItem : TSpkGridColumn);

begin
inherited SetItem(index,AItem);
end;

function TSpkGridColumns.GetItem(index : integer) : TSpkGridColumn;

begin
result:=inherited GetItem(index) as TSpkGridColumn;
end;

procedure TSpkGridColumns.ColumnVisualsChangedHandler(Sender : TObject);

begin
if assigned(FOnVisualsChanged) then
FOnVisualsChanged(self);
end;

procedure TSpkGridColumns.ColumnChangedHandler(Sender : TObject);

begin
if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

function TSpkGridColumns.GetOwner : TPersistent;

begin
result:=FOwnerGrid;
end;

constructor TSpkGridColumns.create(AOwnerGrid : TSpkGrid);

begin
inherited create(TSpkGridColumn);
FOwnerGrid:=AOwnerGrid;
FOnColumnsChanged:=nil;
FOnVisualsChanged:=nil;
end;

destructor TSpkGridColumns.destroy;

begin
inherited destroy;
end;

function TSpkGridColumns.Add : TSpkGridColumn;

begin
result:=TSpkGridColumn(inherited Add);

if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

procedure TSpkGridColumns.Delete(index : integer);

begin
inherited Delete(index);
if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

procedure TSpkGridColumns.Assign(Target : TPersistent);

begin
inherited Assign(Target);

if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

procedure TSpkGridColumns.Update(item : TCollectionItem);

begin
inherited Update(item);

if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

function TSpkGridColumns.Insert(Index: Integer): TSpkGridColumn;

begin
result:=TSpkGridColumn(inherited insert(index));
if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

{ TSpkGrid }

procedure TSpkGrid.ColumnsChangedHandler(Sender : TObject);

begin
RebuildColumns;

if assigned(FOnColumnsChanged) then
FOnColumnsChanged(self);
end;

procedure TSpkGrid.ColumnVisualsChangedHandler(Sender : TObject);

var i : integer;
wd : integer;

begin
if FColumns.count>0 then
begin
// Header
for i:=0 to FColumns.count-1 do
begin
with FHeaders.Sections.Items[i] do
begin
if Width<>FColumns.items[i].Width then
Width:=FColumns.items[i].Width;
if Text<>FColumns.items[i].Caption then
Text:=FColumns.items[i].Caption;
end;
end;

// Edity
wd:=0;
for i:=0 to FColumns.count-1 do
begin
with FEditList[i] do
begin
if left<>wd then
Left:=wd;
if Width<>FColumns.items[i].Width then
Width:=FColumns.items[i].Width;
wd:=wd+FColumns.items[i].Width;
end;
end;
end;

if FColumns.count>0 then
for i:=0 to FColumns.count-1 do
FGrid.ColWidths[i]:=FColumns.Items[i].Width-1;

FGrid.Repaint;

if assigned(FOnColumnVisualsChanged) then
FOnColumnVisualsChanged(self);
end;

procedure TSpkGrid.TopLeftChangedHandler(Sender : TObject);

begin
if (Sender as TStringGrid).LeftCol<>0 then
(Sender as TStringGrid).LeftCol:=0;
end;

procedure TSpkGrid.SectionResizeHandler(HeaderControl: THeaderControl;
Section: THeaderSection);

var i,wd : integer;

begin
FColumns.items[Section.Index].Width:=Section.width;

// Rewymiarowanie komponentów
if FColumns.count>0 then
begin
// Header
for i:=0 to FColumns.count-1 do
begin
with FHeaders.Sections.Items[i] do
begin
if Width<>FColumns.items[i].Width then
Width:=FColumns.items[i].Width;
if Text<>FColumns.items[i].Caption then
Text:=FColumns.items[i].Caption;
end;
end;

// Edity
wd:=0;
for i:=0 to FColumns.count-1 do
begin
with FEditList[i] do
begin
if left<>wd then
Left:=wd;
if Width<>FColumns.items[i].Width then
Width:=FColumns.items[i].Width;
wd:=wd+FColumns.items[i].Width;
end;
end;
end;

if FColumns.count>0 then
for i:=0 to FColumns.count-1 do
FGrid.ColWidths[i]:=FColumns.Items[i].Width-1;

FGrid.Repaint;

if assigned(FOnColumnVisualsChanged) then
FOnColumnVisualsChanged(self);
end;

procedure TSpkGrid.RebuildColumns;

var i : integer;
wd : integer;

begin
// Usuwamy zbędne edity
while length(FEditList)>FColumns.Count do
begin
FEditList[high(FEditList)].free;
setlength(FEditList,length(FEditList)-1);
end;

// Dodajemy potrzebne edity
while length(FEditList)<FColumns.count do
begin
setlength(FEditList,length(FEditList)+1);
FEditList[high(FEditList)]:=TEdit.create(FEditPanel);
FEditList[high(FEditList)].parent:=FEditPanel;
end;

// Ustawiamy odpowiednie pozycje editów
wd:=0;
if length(FEditList)>0 then
for i:=0 to length(FEditList)-1 do
begin
FEditList[i].left:=wd;
FEditList[i].width:=FColumns.Items[i].width;
wd:=wd+FColumns.Items[i].width;
FEditList[i].height:=21;
end;

// Ustawiamy odpowiednie opcje Headera
FHeaders.Sections.Clear;
if FColumns.count>0 then
for i:=0 to FColumns.count-1 do
begin
with FHeaders.Sections.Add do
begin
if Width<>FColumns.items[i].Width then
Width:=FColumns.items[i].Width;
if Text<>FColumns.items[i].Caption then
Text:=FColumns.items[i].Caption;
end;
end;

// Zmieniamy ustawienia Grida
// Ustawiam na 1, bo na 0 się nie da ;]
// Tak czy inaczej, gdy FColumns.count=0, Items nie pozwolą dostać się do
// tego zerowego wiersza, więc wszystko będzie w porządku.
FGrid.ColCount:=max(1,FColumns.count);
// Rows zostawiamy w spokoju
if FColumns.count>0 then
for i:=0 to FColumns.count-1 do
FGrid.ColWidths[i]:=FColumns.Items[i].Width-1;
end;

procedure TSpkGrid.SetColumns(Value : TSpkGridColumns);

begin
FColumns.Assign(Value);
end;

constructor TSpkGrid.create(AOwner : TComponent);

begin
inherited create(AOwner);
BevelInner:=bvNone;
BevelOuter:=bvNone;

// Własności
FOnColumnsChanged:=nil;

FColumns:=TSpkGridColumns.create(self);
FColumns.OnColumnsChanged:=self.ColumnsChangedHandler;
FColumns.OnVisualsChanged:=self.ColumnVisualsChangedHandler;

// Nagłówki
FHeaders:=THeaderControl.create(self);
FHeaders.parent:=self;
FHeaders.align:=alTop;
FHeaders.OnSectionResize:=self.SectionResizeHandler;

// Panel dla editów
FEditPanel:=TPanel.create(self);
FEditPanel.parent:=self;
FEditPanel.top:=FHeaders.top+FHeaders.height+1;
FEditPanel.align:=alTop;
FEditPanel.BevelInner:=bvNone;
FEditPanel.BevelOuter:=bvNone;
FEditPanel.height:=21;

// StringGrid
FGrid:=TStringGrid.create(self);
FGrid.parent:=self;
FGrid.top:=FEditPanel.top+FEditPanel.height+1;
FGrid.align:=alClient;
FGrid.BorderStyle:=bsNone;
FGrid.ScrollBars:=ssVertical;
FGrid.FixedCols:=0;
FGrid.FixedRows:=0;
FGrid.OnTopLeftChanged:=self.TopLeftChangedHandler;
FGrid.Options:=[goFixedVertLine,
goFixedHorzLine,
goVertLine,
goHorzLine,
goRowSelect];
end;

destructor TSpkGrid.destroy;

begin
FColumns.clear;
FColumns.Free;

// Pozostałe dynamicznie utworzone komponenty są odpowiednio "zownerowane",
więc
// zostaną zwolnione automatem - w tym edity leżące na FEditPanelu.

inherited destroy;
end;

end.
</code>

With best regards -- Spook.

--
! ._______. Warning: Lucida Console sig! //) !
! || spk || www.spook.freshsite.pl / _ """*!
! ||_____|| spook at op.pl / ' | ""!
! | ___ | tlen: spoko_ws gg:1290136 /. __/"\ '!
! |_|[]_|_| May the SOURCE be with you! \/) \ !
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi VCL Components Writing All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.