0
votes

I am trying to make use of the Objects property of the Stringgrid inside my descendant and I think I am doing something wrong. So, I created a simple class for use in my StringGrid cells, something like:

type

  TKind = (tkNone,tkStart, tkEnd, tkMiddle);

  TMyCell = class(TObject)
  private
    FKind:string; // TKind: start, middle, end, none
    FOfType:string; // new, registered, paid, over, none
    FActualDate:TDate; 
    FTheText:string; // if you want to show a text in it
    FIsWeekend:Boolean;
    function IsItWeekend(dt:Tdate):boolean;
    procedure setKind(s:string);
    { Private declarations }
  protected
    { Protected declarations }
  public
    constructor Create;
    property Kind:string read FKind write setKind;
    property OfType:string read FOfType write FOfType;
    property ActualDate:TDate read FActualDate write FActualDate;
    property TheText:string read FTheText write FTheText;
    property IsWeekend:Boolean read FIsWeekend write FIsWeekend default false;
    { Public declarations }
  published
    { Published declarations }
  end;


implementation

procedure TMyCell.setKind(s:string);
begin
  FKind:=s;
end;

function TMyCell.IsItWeekend(dt:Tdate):boolean;
begin
  if (DayOfTheWeek(dt)=6) or (DayOfTheWeek(dt)=7) then IsItWeekend:=true else IsItWeekend:=false;    
end;

constructor TMyCell.Create;
var
  i:integer;
  a,l,z:word;
  dt:TDate;
begin
  FKind:='none';
  FOfType:='none';
  FActualDate:=now;
  FTheText:='';
  FIsWeekend:=IsItWeekend(FActualDate);
end;

then, in my StringGrid descendant (TMyGrid), I do the following:

 TMyGrid = class(TStringGrid)
  private
    FStartSelection:integer;
    FFixedColor:TColor;
    FRowCount:integer;
  ...
  published
    property ColCount;
    property RowCount;
  ...

constructor TMyGrid.Create(AOwner: TComponent);
var
  i:integer;
  a,l,z:word;
  dt:TDate;
  j: Integer;
  myCell:TMyCell;
begin
  inherited;
  ...// different settings
  RowCount:=5;
  for i := 0 to colCount-1 do
    for j := 0 to RowCount-1 do
      begin
        Objects[i, j] := TMyCell.Create;
      end;
end;

destructor TMyGrid.Destroy;
var
  i,j:integer;
begin
  for i := 0 to colCount-1 do
    for j := 0 to RowCount-1 do
      begin
        TMyCell(Objects[i, j]).Free;
      end;
  inherited;
end;

... // other stuff

procedure Register;
begin
  RegisterComponents('mygrid', [TMyGrid]);
end;

The problem is I don't know how do I tell my control that there are more rows when the developer changes the RowCount in the objectInspector before running the app. So I drop my StrinGrid descendant on a form, and set the rowCount to 10. But my StringGrid does not have Objects created for the new rows, So the cells on ARow=5->9 do not have objects created... because in OnCreate I only set the initial value of the RowCount to 5 and create objects for i:=0 to RowCount-1.

Is there an event or method where I can tell the StringGrid to create the Objects after the developer changes the rowCount in ObjectInspector?

I am sure that this is my problem because, using the above code, when I drop my stringGrid on a form and set it's rowCount (design time or runtime) to 10 then I want to assign a value to Kind property of a cell that is on a Row>4 I get an AccessViolation, but if I do that for a row that is <= 4 the assignment works just fine.

I found something that should help here: http://embarcadero.newsgroups.archived.at/public.delphi.ide/200904/0904193279.html but I do not know how and where to place this code in my StringGrid descendant class so it would get called when RowCount is changed at designtime/runtime

EDIT

After reading your comments I tried your idea (that seemed to work) to override the SizeChanged (I did not know that method existed, must have skipped it when I serached before). Anyway, I added this code to my class:

TMyGrid = class(TStringGrid)
  private
    ...
    procedure SizeChanged(OldColCount, OldRowCount: Longint); override;
    procedure UpdateGridDimensions(NewColCount, NewRowCount: Integer);
    ...

procedure TMyGrid.SizeChanged(OldColCount, OldRowCount: Longint);
begin
  inherited;
  if (OldRowCount<>FRowCount)or(OldColCount<>ColCount) then
    UpdateGridDimensions(ColCount, FRowCount);
end;


procedure TMyGrid.UpdateGridDimensions(NewColCount, NewRowCount: Integer);
 var
    C, R: Integer;
    Old: Integer;
 begin
    if NewColCount <> ColCount then
    begin
        if NewColCount < ColCount then
        begin
            for R := 0 to RowCount-1 do
            begin
                for C := ColCount-1 downto NewColCount do
                    Objects[C, R].Free;
            end;
        end;

        Old := ColCount;
        ColCount := NewColCount;

        if NewColCount > Old then
        begin
            for R := 0 to RowCount-1 do
            begin
                for C := Old to NewColCount-1 do
                    Objects[C, R] := TMyCell.Create;
            end;
        end;
    end;

    if NewRowCount <> RowCount then
    begin
        if NewRowCount < RowCount then
        begin
            for C := 0 to ColCount-1 do
            begin
                for R := RowCount-1 downto NewRowCount do
                    Objects[C, R].Free;
            end;
        end;

        Old := RowCount;
        RowCount := NewColCount;

        if NewRowCount > Old then
      begin
            for C := 0 to ColCount-1 do
            begin
                for R := Old to NewRowCount-1 do
                    Objects[C, R] := TMyCell.Create;
            end;
        end;
    end;
 end;

but now whenever I drop my control on a form, the rowcount is 93... where do I set that rowCount? Because I DONT.

And still, if I increase the RowCount from 93 to something else like 100, then my Objects exist for the first 93 rows but they do not get created for the 93-100 rows...

So the idea sounded great, but it does not work as I expect it...

Any thoughts? Am I doing it wrong?

1
To detect when you are in designtime mode: Component Initialization - Runtime vs. Designtime. - LU RD
I think you can override dynamic method SizeChanged and initialize grid properly according to new size. - Andrei Galatyn
Don't use Objects[]. That's for the consumer not the component author. - David Heffernan
I was trying to give the consumer a component ready to fill with data, and save him from creating new classwes and objects. Especially because the purpose of my coimponent will be a specific one, so the consumer wont need to implement different classes for the cell's object. But I get your point - user1137313
This question now is quite a mess. I think you need to get back to basics. There are an awful lot of mistakes here. - David Heffernan

1 Answers

0
votes
// SizeChanged - Called when the size of the grid has changed.
protected
  procedure SizeChanged(OldColCount, OldRowCount: Longint); dynamic;

You can override dynamic method SizeChanged and initialize grid according to new size. You can check is it designtime or not (LU RD suggested link). And as David mentioned, it is better to keep Objects property for consumers of component. Create and use your own TList/TObjectList instead.