TStringGrid
has a TGridOption goColSizing
that allows for automatic resizing of columns at runtime when you drag in the margin between the columns. Is there a corresponding event that is triggered when a column size occurs? I'd like to resize another component to match the size/location of a certain column should the column sizes change.

- 8,222
- 7
- 46
- 82
3 Answers
So far as I can tell, no event is surfaced to notify you of such a modification. I think that the best you can do is to sub-class the control and override the ColWidthsChanged
method:
Responds when the column widths change.
ColWidthsChanged is called immediately after the column widths change. The change can result from setting the ColWidths property, from setting the DefaultColWidth property, from moving one of the columns, or from resizing the columns with the mouse.
Since sub-classing a control is a very heavy weight operation, it might be prudent to sub-class once and override this method in order to surface an event.

- 601,492
- 42
- 1,072
- 1,490
-
It's not so heavy weight operation in my opinion. You can do it like [this](https://stackoverflow.com/questions/14783400/delphi-subclass-visual-component-and-use-it) – Vassilis Jan 23 '20 at 16:20
-
I mean, I know how to do it, but I would still regard that as quite intrusive – David Heffernan Jan 23 '20 at 16:25
I have found another solution that is even easier, one that relies on a Delphi oddity: helper functions get private access. If we define helper class for TCustomerGrid (we have to 'help' TCustomGrid rather than TStringGrid because that is where the private fields are):
TCustomGridHelper = class helper for TCustomGrid
function GetGridState : TGridState;
function GetSizingIndex : Integer;
end;
function TCustomGridHelper.GetGridState: TGridState;
begin
Result := Self.FGridState;
end;
function TCustomGridHelper.GetSizingIndex: Integer;
begin
Result := Self.FSizingIndex;
end;
Now, to use it we just do:
procedure TSomeForm.ProductAllowedGridMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
col, row: Integer;
grid: TStringGrid;
begin
if Button = mbLeft then begin
grid := TStringGrid(Sender);
if grid.GetGridState = gsColSizing then begin
// display column and new size
Caption := IntToStr(grid.GetSizingIndex) + ': ' + IntToStr(grid.ColWidths[grid.GetSizingIndex]);
end;
end;
end;

- 3,315
- 1
- 24
- 35
-
Nice! I hadn't thought of doing it like that, but indeed a very clean solution. – jdetaeye Apr 28 '16 at 08:45
-
Doesn't work with Delphi 2007 unfortunately. I had to hack into the class with `Result := THackGrid (Self).FGridState ;` and that compiles, but `Result := THackGrid (Self).FSizingIndex ;` gives an error: `Cannot access private symbol "FSizingIndex"`. Looking at the VCL source for TCustomGrid I see that `FGridState` is declared as `protected` but FSizingIndex is `private`. – rossmcm Sep 28 '21 at 03:39
Maybe I'm a little late with my answer but I stumbled upon the same problem and have found an easier solution if you'd rather not subclass TStringGrid. My solution involves using Rtti in the OnMouseUp event to retrieve the value of the protected field FGridState from TCustomGrid.
Note that I have my own Rtti class with some class functions that make it easier to use Rtti throughout my program code.
class function TRttiUtils.GetClassField(aClass: TClass;
aFieldName: String): TRttiField;
var
Fields: TArray<TRttiField>;
Field: TRttiField;
begin
Result := nil;
Fields := GetClassFields(aClass);
For Field in Fields do
If Field.Name = aFieldName
then begin
Result := Field;
break;
end;
end;
class function TRttiUtils.GetClassFields(aClass: TClass): TArray<TRttiField>;
var
RttiContext: TRttiContext;
RttiType: TRttiInstanceType;
Fields: TArray<TRttiField>;
begin
RttiContext := TRttiContext.Create;
RttiType := RttiContext.GetType(aClass) as TRttiInstanceType;
Fields := RttiType.GetFields;
Result := Fields;
end;
These are the two class functions that I use in my OnMouseUp event for the stringgrid.
procedure TFrameCurrency.sgCurrenciesMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
R: TPoint;
Row, Col: Integer;
GridStateField: TRttiField;
GridState: TGridState;
ColSizing: Boolean;
begin
inherited;
If Button = mbLeft
then begin
//Determine row and column
(Sender As TStringGrid).MouseToCell(X, Y, R.X, R.Y);
Row := R.Y;
Col := R.X;
//Check if it is ColSizing
ColSizing := False;
GridStateField := TRttiUtils.GetClassField(TStringGrid, 'FGridState');
If Assigned(GridStateField)
then begin
GridState := GridStateField.GetValue(sgCurrencies).AsType<TGridState>;
If GridState = gsColSizing
then begin
//specific code comes here
ColSizing := True;
end;
end;
If Not ColSizing
then begin
//sorting logic comes here
end;
end;
end;
I think this is a cleaner and easier solution than having to subclass TStringGrid.

- 183
- 1
- 13