3
votes

This Question is similar to how-to-find-the-actual-width-of-grid-component-with-scrollbar-in-delphi

but i couldn't get the CalcDrawInfo(DrawInfo); to work with a StringGrid

For example if you add a StringGrid and randomly set the RowCount and ColCount values at FormCreate
Can you get the actual size of this component so that if you set the Width and Height, the scrollbars would disappear and if your screen was big enough you could see all the StringGrid

Im guessing that in the case of a StringGrid you could calculate the width and height by looping through the columns getting the info and adding them up.
i was just wondering if its possible to hijack something that the scroll bar does to calculate its position so it knows what part of the component to paint,
or some Draw function that can return the full range of the component

if possible can you get a double click on the string grid calculating the actual height and width in the example below


Start a new Delphi VCL Forms Application
Copy below and paste into the main form

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

Hook up the FormCreate and StringGrid DblClick event

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;

get the double click returning the actual range of the component so that if the width and height was reset the scroll bars are no longer visible

1

1 Answers

1
votes

The method you would need (CalcDrawInfoXY) is unfortunately declared private in TCustomGrid. Replicating it is simple enough, however :

Declare a hack class to expose CalcFixedInfo, introduce your own method to replicate CalcDrawInfoXY.

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

and implement as (from 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;

This allows you to get TGridDrawInfo for an imaginary canvas size. Using a suitably large imaginary canvas you can get the full extent of the grid :

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;

Here I've used MaxInt - 1, which should be large enough to accomodate almost anything sane. MaxInt doesn't work as an argument, the DrawInfo will return MaxInt for the grid size if you do. This is essentially doing what you suggest in your question, which is iterating over the rows and columns to measure the total size of the grid.