如何判断FMX StringGrid中的列是否被调整大小?
Hey there! I’ve dealt with this exact issue before when working with FMX StringGrids—since there’s no built-in OnColumnResized event out of the box, we’ve got a couple of solid workarounds to detect when a column’s width gets adjusted. Let me break them down for you:
Method 1: Track Column Widths with Mouse Events (Quick & Simple)
This approach is great if you want a no-fuss implementation without modifying the grid class. We’ll store the initial column widths, then check for changes when the user releases the mouse (since column resizing happens via dragging the column divider).
First, add a private field to your form to track original widths:
type TForm1 = class(TForm) StringGrid1: TStringGrid; procedure FormCreate(Sender: TObject); procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); private FOriginalColWidths: TArray<Integer>; // Stores initial column widths public { Public declarations } end;
Initialize the width array when the form loads:
procedure TForm1.FormCreate(Sender: TObject); var I: Integer; begin // Initialize array with current column widths SetLength(FOriginalColWidths, StringGrid1.ColumnCount); for I := 0 to StringGrid1.ColumnCount - 1 do FOriginalColWidths[I] := StringGrid1.Columns[I].Width; end;
Then, check for width changes in the grid’s OnMouseUp event:
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); var I: Integer; CurrentCol: TColumn; begin // Only check left mouse button releases (since that's what's used for resizing) if Button = TMouseButton.mbLeft then begin for I := 0 to StringGrid1.ColumnCount - 1 do begin CurrentCol := StringGrid1.Columns[I]; if CurrentCol.Width <> FOriginalColWidths[I] then begin // Column I was resized! Do your logic here ShowMessage(Format('Column %d resized from %d to %d', [I, FOriginalColWidths[I], CurrentCol.Width])); // Update the stored width to match the new size for future checks FOriginalColWidths[I] := CurrentCol.Width; end; end; end; end;
Notes for Method 1:
- This will catch resizes even if the user drags the divider back to the original width (but the comparison will just skip triggering your logic in that case).
- It’s a bit of a brute-force approach since it checks all columns on every mouse up, but it’s perfect for small grids or simple use cases.
Method 2: Subclass TStringGrid for Precise Detection (Cleaner & More Efficient)
If you want a more elegant solution that directly hooks into the grid’s internal resizing logic, subclassing TStringGrid is the way to go. We’ll override the ResizeColumn method (which is called internally when a column’s width is changed) and add a custom event for resizing.
First, create the subclass in your unit:
type // Define a custom event type to pass resize details TColumnResizedEvent = procedure(Sender: TObject; ACol: Integer; OldWidth, NewWidth: Integer) of object; TMyStringGrid = class(TStringGrid) private FOnColumnResized: TColumnResizedEvent; FOldColWidths: TArray<Integer>; procedure DoColumnResized(ACol: Integer; OldWidth, NewWidth: Integer); protected procedure ResizeColumn(ACol: Integer; ANewWidth: Integer); override; procedure CreateWnd; override; public property OnColumnResized: TColumnResizedEvent read FOnColumnResized write FOnColumnResized; end;
Implement the subclass methods:
procedure TMyStringGrid.CreateWnd; var I: Integer; begin inherited; // Initialize stored widths when the grid is created SetLength(FOldColWidths, ColumnCount); for I := 0 to ColumnCount - 1 do FOldColWidths[I] := Columns[I].Width; end; procedure TMyStringGrid.ResizeColumn(ACol: Integer; ANewWidth: Integer); var OldColWidth: Integer; begin OldColWidth := FOldColWidths[ACol]; // Let the grid handle the resize first inherited; // Only trigger the event if the width actually changed if ANewWidth <> OldColWidth then begin FOldColWidths[ACol] := ANewWidth; DoColumnResized(ACol, OldColWidth, ANewWidth); end; end; procedure TMyStringGrid.DoColumnResized(ACol: Integer; OldWidth, NewWidth: Integer); begin // Fire the custom event if a handler is assigned if Assigned(FOnColumnResized) then FOnColumnResized(Self, ACol, OldWidth, NewWidth); end;
Now, replace your form’s TStringGrid with TMyStringGrid (you can do this in the form designer by right-clicking the grid, selecting "Class Name", and entering TMyStringGrid), then assign the custom event:
procedure TForm1.MyStringGrid1ColumnResized(Sender: TObject; ACol: Integer; OldWidth, NewWidth: Integer); begin // Handle the resize event here—you get the exact column and width changes! ShowMessage(Format('Column %d resized: %d → %d', [ACol, OldWidth, NewWidth])); end;
Notes for Method 2:
- This approach is far more efficient since it only triggers when an actual resize happens, no need to loop through all columns.
- The custom event gives you direct access to the column index and old/new widths, making it easier to handle specific columns.
内容的提问来源于stack exchange,提问作者R.Nowee

