TStringGrid
有一个 TGridOption goColSizing
,当您拖动列之间的边距时,可以在运行时自动调整列的大小。当列大小发生时是否有相应的事件被触发?如果列大小发生变化,我想调整另一个组件的大小以匹配特定列的大小/位置。
据我所知,没有任何事件通知您此类修改。我认为你能做的最好的事情就是对控件进行子类化并覆盖
ColWidthsChanged
方法:
当列宽改变时做出响应。
ColWidthsChanged 在列宽更改后立即调用。更改可以通过设置 ColWidths 属性、设置 DefaultColWidth 属性、移动其中一列或使用鼠标调整列大小来实现。
由于对控件进行子类化是一项非常繁重的操作,因此谨慎的做法可能是对控件进行子类化并重写此方法以显示事件。
我发现了另一种更简单的解决方案,它依赖于 Delphi 的一个奇怪之处:辅助函数获得私有访问。如果我们为 TCustomerGrid 定义帮助程序类(我们必须“帮助”TCustomGrid 而不是 TStringGrid,因为那是私有字段所在的位置):
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;
现在,要使用它,我们只需:
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;
也许我的回答有点晚了,但我偶然发现了同样的问题,并且如果您不想继承 TStringGrid 的子类,则找到了更简单的解决方案。 我的解决方案涉及在 OnMouseUp 事件中使用 Rtti 从 TCustomGrid 检索受保护字段 FGridState 的值。
请注意,我有自己的 Rtti 类,其中包含一些类函数,可以更轻松地在整个程序代码中使用 Rtti。
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;
这些是我在 stringgrid 的 OnMouseUp 事件中使用的两个类函数。
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;
我认为这是一个比必须子类化 TStringGrid 更干净、更简单的解决方案。
基于 jdetaeye 发布的内容,为了支持 TDBGrids,我发现 MouseToCell 不可靠,并通过以下修改解决了它。
procedure TForm.DBGridMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button <> mbLeft then
Exit;
var GridStateField := TRttiUtils.GetClassField(TCustomGrid, 'FGridState');
if GridStateField=nil then
Exit;
if GridStateField.GetValue(Sender).AsType<TGridState> <> gsColSizing then
Exit;
var SizingIndexField := TRttiUtils.GetClassField(TCustomGrid, 'FSizingIndex');
if SizingIndexField=nil then
Exit;
var Col:=SizingIndexField.GetValue(Sender).AsType<LongInt>;
OutputDebugString(PChar('Sizing Column '+Col.ToString));
end;