【发布时间】:2015-02-15 23:00:44
【问题描述】:
TStringGrid 有一个 TGridOption goColSizing,当您在列之间拖动时,它允许在运行时自动调整列的大小。发生列大小时是否会触发相应的事件?如果列大小发生变化,我想调整另一个组件的大小以匹配某个列的大小/位置。
【问题讨论】:
标签: delphi tstringgrid
TStringGrid 有一个 TGridOption goColSizing,当您在列之间拖动时,它允许在运行时自动调整列的大小。发生列大小时是否会触发相应的事件?如果列大小发生变化,我想调整另一个组件的大小以匹配某个列的大小/位置。
【问题讨论】:
标签: delphi tstringgrid
据我所知,没有出现任何事件来通知您此类修改。我认为您能做的最好的事情就是对控件进行子类化并覆盖ColWidthsChanged 方法:
当列宽改变时响应。
ColWidthsChanged 在列宽更改后立即调用。更改可能来自设置 ColWidths 属性、设置 DefaultColWidth 属性、移动其中一列或使用鼠标调整列大小。
由于对控件进行子类化是一项非常繁重的操作,因此最好进行一次子类化并重写此方法以显示事件。
【讨论】:
也许我的回答有点晚了,但我偶然发现了同样的问题,如果你不想继承 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;
这是我在 OnMouseUp 事件中为 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;
我认为这是一个比必须继承 TStringGrid 更清洁、更简单的解决方案。
【讨论】:
我找到了另一种更简单的解决方案,它依赖于 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;
【讨论】:
Result := THackGrid (Self).FGridState ; 破解类并编译,但Result := THackGrid (Self).FSizingIndex ; 给出错误:Cannot access private symbol "FSizingIndex"。查看 TCustomGrid 的 VCL 源代码,我看到 FGridState 被声明为 protected 但 FSizingIndex 是 private。