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.
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.
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.
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;