Delphi 从具有滚动条的组件中获得实际完整 height/Width

Delphi get actual full height/Width off a component that has scrollbar

这个问题类似于 how-to-find-the-actual-width-of-grid-component-with-scrollbar-in-delphi

但是我无法获取 CalcDrawInfo(DrawInfo);使用 StringGrid

例如,如果您添加一个 StringGrid 并在 FormCreate 中随机设置 RowCount 和 ColCount 值
你能得到这个组件的实际大小吗,这样如果你设置宽度和高度,滚动条就会消失,如果你的屏幕足够大,你可以看到所有的 StringGrid

我猜想在 StringGrid 的情况下,您可以通过遍历列获取信息并将它们相加来计算宽度和高度。
我只是想知道是否可以劫持一些东西滚动条确实会计算其位置,因此它知道要绘制组件的哪一部分,
或者一些可以 return 整个组件范围

的 Draw 函数

如果可能的话,您可以双击字符串网格来计算下面示例中的实际高度和宽度


开始新的 Delphi VCL 表单申请
复制下面并粘贴到主窗体

object strngrd1: TStringGrid
  Left = 0
  Top = 0
  Width = 200
  Height = 150
  ColCount = 12
  RowCount = 13
  TabOrder = 0
  OnDblClick = strngrd1DblClick
end

连接 FormCreate 和 StringGrid DblClick 事件

procedure TfrmMain.FormCreate(Sender: TObject);
var i, iMax : Integer;
begin
  strngrd1.RowCount := Random(100);
  strngrd1.ColCount := Random(100);
  iMax := strngrd1.RowCount;
  if strngrd1.ColCount > iMax then
  iMax := strngrd1.ColCount;

  for I := 0 to iMax -1 do begin
    if i < strngrd1.RowCount then
      strngrd1.Rows[i].Text := i.ToString;
    if i < strngrd1.ColCount then
      strngrd1.Cols[i].Text := i.ToString;
  end;
end;

procedure TfrmMain.strngrd1DblClick(Sender: TObject);
var iActualWidth, iActualHeight : Integer;
    sActualWidth, sActualHeight : String;
begin
  iActualWidth  := 0;
  iActualHeight := 0;
  sActualWidth  := '??';
  sActualHeight := '??';

  if iActualHeight > 0 then
    sActualHeight := iActualHeight.ToString;
  if iActualWidth > 0 then
    sActualWidth := iActualWidth.ToString;

  ShowMessage(strngrd1.ClassType.ClassName + #13#10 +
              'Current Width = ' + strngrd1.Width.ToString + #13#10 +
              'Current Height = ' + strngrd1.Height.ToString + #13#10 +
              'Client Width = ' + strngrd1.ClientWidth.ToString + #13#10 +
              'Client Height = ' + strngrd1.ClientHeight.ToString + #13#10 +
              'Actual Width = ' + sActualWidth + #13#10 +
              'Actual Height = ' + sActualHeight + #13#10 );
end;

双击 return 组件的实际范围,以便在重置宽度和高度后滚动条不再可见

不幸的是,您需要的方法 (CalcDrawInfoXY) 已在 TCustomGrid 中声明为 private。复制它很简单,但是:

声明一个 hack class 来暴露 CalcFixedInfo,介绍你自己的方法来复制 CalcDrawInfoXY

TGridHack = class(TCustomGrid)
  procedure GetDrawInfoXY(var DrawInfo: TGridDrawInfo; UseWidth, UseHeight: Integer);
end;

并实施为(来自 Vcl.Grids)

procedure TGridHack.GetDrawInfoXY(var DrawInfo: TGridDrawInfo; 
                                  UseWidth, UseHeight: Integer);
  procedure CalcAxis(var AxisInfo: TGridAxisDrawInfo; UseExtent: Integer);
  var
    I: Integer;
  begin
    with AxisInfo do
    begin
      GridExtent := UseExtent;
      GridBoundary := FixedBoundary;
      FullVisBoundary := FixedBoundary;
      LastFullVisibleCell := FirstGridCell;
      for I := FirstGridCell to GridCellCount - 1 do
      begin
        Inc(GridBoundary, AxisInfo.GetExtent(I) + EffectiveLineWidth);
        if GridBoundary > GridExtent + EffectiveLineWidth then
        begin
          GridBoundary := GridExtent;
          Break;
        end;
        LastFullVisibleCell := I;
        FullVisBoundary := GridBoundary;
      end;
    end;
  end;
begin
  CalcFixedInfo(DrawInfo);
  CalcAxis(DrawInfo.Horz, UseWidth);
  CalcAxis(DrawInfo.Vert, UseHeight);
end;

这允许您获得 TGridDrawInfo 假想的 canvas 尺寸。使用适当大的虚数 canvas 您可以获得网格的完整范围:

procedure TForm1.strngrd1DblClick(Sender: TObject);
var iActualWidth, iActualHeight : Integer;
    sActualWidth, sActualHeight : String;
    DrawInfo : TGridDrawInfo;
begin
  TGridHack(strngrd1).GetDrawInfoXY(DrawInfo, MaxInt - 1, MaxInt - 1);
  iActualWidth  := DrawInfo.Horz.GridBoundary;
  iActualHeight := DrawInfo.Vert.GridBoundary;
  sActualWidth  := iActualWidth.ToString;
  sActualHeight := iActualHeight.ToString;


  ShowMessage(strngrd1.ClassType.ClassName + #13#10 +
              'Current Width = ' + strngrd1.Width.ToString + #13#10 +
              'Current Height = ' + strngrd1.Height.ToString + #13#10 +
              'Client Width = ' + strngrd1.ClientWidth.ToString + #13#10 +
              'Client Height = ' + strngrd1.ClientHeight.ToString + #13#10 +
              'Actual Width = ' + sActualWidth + #13#10 +
              'Actual Height = ' + sActualHeight + #13#10 );
end;

我在这里使用了 MaxInt - 1,它应该足够大以容纳几乎所有理智的东西。 MaxInt 不能用作参数,如果您这样做,DrawInfo 将 return MaxInt 作为网格大小。这实际上是按照您在问题中提出的建议进行操作,即遍历行和列以测量网格的总大小。