In Delphi, how can I create a class derived from the TStringGrid class such that the TObject array associated with the grids cells is of a more specific type for example TColor which would be used to specify the colour of the cell?
Asked
Active
Viewed 337 times
1
-
You might want to observe -- given the wording "a more specific type" -- that the Delphi `TColor` type isn't a class and so doesn't belong to any class hierarchy. A `TColor` isn't a `TObject`. It so happens, however, that a `TColor` is a 32-bit integer and therefore fits into a `TObject` (=pointer) variable on all platforms used today (32 bit and 64 bit). `TButton`, `TBitmap`, and `TStringList` *are* classes, however, so a `TStringList` instance *is* a `TObject`. – Andreas Rejbrand Feb 05 '21 at 10:21
2 Answers
6
type
TStringColorGrid = class(TStringGrid)
private
function GetColor(ACol, ARow: Integer): TColor;
procedure SetColor(ACol, ARow: Integer; AValue: TColor);
public
property Colors[ACol, ARow: Integer]: TColor read GetColor write SetColor;
end;
function TStringColorGrid.GetColor(ACol, ARow: Integer): TColor;
begin
Result := TColor(inherited Objects[ACol, ARow]);
end;
procedure TStringColorGrid.SetColor(ACol, ARow: Integer; AValue: TColor);
begin
inherited Objects[ACol, ARow] := TObject(AValue);
end;

Remy Lebeau
- 555,201
- 31
- 458
- 770
-
As I said in my answer, that is only correct for data that has the same size as a pointer. The OP said TColor was just an example. – fpiette Feb 05 '21 at 09:24
-
5@fpiette it will work fine for types *up to* the size of a pointer, they can be smaller. On a 32bit system, Int64 won't work, for instance. Also, extra care has to be taken for reference-counted types, like strings and interfaces. But this is just one example of how to implement a custom property to work with a different type than TObject. – Remy Lebeau Feb 05 '21 at 09:31
2
TStringGrid can hold a TObject for each cell. TColor doesn't inherit from TObject so it doesn't work.
You could cast a TColor to a TObject but this would be a bad solution prone to future issues. And this would not work for any type (Only those having at most the size of a pointer).
The best solution is to "box" your data into a TObject and save the instance of such an object into the StringGrid.
TMyBoxingColorObject = class
Data : TColor; // Or any other datatype
end;
Don't forget to create and free the object as needed!
You can also use generics if you have a lot of different types to box.

fpiette
- 11,983
- 1
- 24
- 46
-
1"*prone to future issues*" - only if Delphi ever makes `TObject` use ARC again. Which given Embarcadero's backpeddling on that feature in 10.4, is unlikely to happen again anytime soon, if ever. "*The best solution is to "box" your data*" - the problem with boxing is ownership. Who owns the box objects and should free them? `TStringGrid` is not virtual enough to do that reliably solely in a descendant, putting burden on the user, and defeating the purpose of making a descendant at all. – Remy Lebeau Feb 05 '21 at 08:15
-
I'd say it is fairly idiomatic in Delphi to use `Tag`, (list view item) `Data`, `Objects[i]` etc. to store anything that fits in a native-sized integer. (Also, saying that "TColor doesn't inherit from TObject" is a bit misleading, since TColor doesn't inherit from anything.) Still, your suggestion is great if you need to store more data than you can fit in a native-sized integer. – Andreas Rejbrand Feb 05 '21 at 08:20
-
I am hoping that once created, the following grid.Objects[c,r]. would "know" that I am referring to an object of type TColor and that when I type the fullstop I get options associated with TColor. Is that the expected behaviour? – Tony Wolff Feb 05 '21 at 08:59
-
-
Tony, if you want that, without using a cast, you have to derive a new class from TStringGrid (Or custom one) and expose a new property of the proper boxing type. Personally I use boxing class with success and use a cast: TMyBoxingColorObject(MyStringGrid.Objects[Col, Row]). Then if you add a dot, Delphi show the available items. Depending on your taste, an interposer class could be helpful as well. – fpiette Feb 05 '21 at 09:49
-
@fpiette the FMX StringGrind does not have an Objects property. How do you di this in FMX? – Michael Riley - AKA Gunny Apr 21 '23 at 11:11
-
@MichaelRiley-AKAGunny This is out of scope of the original question. Feel free to ask for a new specific question. That's how StackOverflow works. – fpiette Apr 21 '23 at 13:59