5

I want to adjust a TDBGrid height given a VisibleRows parameter. the grid may or may not have titles.

Suppose I select 100 records from the db, but I want the grid height to adjust to show the first 10 rows (make them visible). the dataset will still hold 100 records.

i.e.

procedure SetVisibleRows(DBGrid: TCustomDBGrid; VisibleRows: Integer);
begin
  ...
  DBGrid.Height := ???
end;

I know how to get the visible rows:

type
  TCustomGridHack = class(TCustomGrid);

function GetVisibleRows(DBGrid: TCustomDBGrid): Integer;
begin
   Result := TCustomGridHack(DBGrid).VisibleRowCount;
end;

But, is there a way to set the VisibleRowCount?

zig
  • 4,524
  • 1
  • 24
  • 68
  • @nil, Thanks. I know it's a read-only property. I actually started with the *"increase or decrease the Height until VisibleRowCount and DesiredVisibleRows are the same"* - but I didn't like it. please see my answer for a possible solution. – zig Nov 15 '17 at 10:56
  • I understand, trying that didn't feel good. What I was trying then was something similar to yours but based on the draw info the grid creates. – nil Nov 15 '17 at 11:10
  • @nil, I did see the `GetVisibleRowCount` method, but is the grid client height could be *set* by `TGridDrawInfo`? I only found calculations of it. If you have a working code feel free to share :) – zig Nov 15 '17 at 11:21
  • Nothing that does more than your code. Besides making the scrollbars behave funky. Was thinking about something like this: – nil Nov 15 '17 at 12:10
  • 1
    procedure SetVisibleRows(DBGrid: TCustomDBGrid; VisibleRows: Integer); var AGridDrawInfo: TGridDrawInfo; AClientHeight: Integer; I: Integer; begin TDBGridAccess(DBGrid).CalcDrawInfo(AGridDrawInfo); AClientHeight := AGridDrawInfo.Vert.FixedBoundary; for I := AGridDrawInfo.Vert.FirstGridCell to VisibleRows do Inc(AClientHeight, (AGridDrawInfo.Vert.GetExtent(I) + AGridDrawInfo.Vert.EffectiveLineWidth)); DBGrid.ClientHeight := AClientHeight; end; – nil Nov 15 '17 at 12:12
  • @nil, Thanks. I have adjusted your code a bit. works fine! – zig Nov 16 '17 at 07:16

1 Answers1

2

This seems to work (maybe could be optimized more):

type
  TCustomDBGridHack = class(TCustomDBGrid);

procedure SetVisibleRows(DBGrid: TCustomDBGrid; VisibleRows: Integer);
var
  TitleHeight, RowHeight: Integer;
begin
  with TCustomDBGridHack(DBGrid) do
  begin
    if dgTitles in Options then
    begin
      TitleHeight := RowHeights[0] + GridLineWidth;
      RowHeight := RowHeights[1] + GridLineWidth;
    end
    else
    begin
      TitleHeight := 0;
      RowHeight := RowHeights[0] + GridLineWidth;
    end;
  end;
  DBGrid.ClientHeight := TitleHeight + (RowHeight * VisibleRows) + 1;
end;

Or by using TGridDrawInfo as suggested by @nil. It produces more accurate results (I modified it a bit):

procedure SetVisibleRows(DBGrid: TCustomDBGrid; VisibleRows: Integer);
var
  DrawInfo: TGridDrawInfo;
  TitleHeight, RowHeight: Integer;
begin
  with TCustomDBGridHack(DBGrid) do
  begin
    CalcDrawInfo(DrawInfo);
    TitleHeight := DrawInfo.Vert.FixedBoundary;
    RowHeight := RowHeights[DrawInfo.Vert.FirstGridCell] + DrawInfo.Vert.EffectiveLineWidth;
  end;
  DBGrid.ClientHeight := TitleHeight + (RowHeight * VisibleRows) + 1;
end;

As mentioned by @nil, RowHeight could be also calculated with:

RowHeight := DrawInfo.Vert.GetExtent(DrawInfo.Vert.FirstGridCell) + DrawInfo.Vert.EffectiveLineWidth; 

I haven't noticed any difference though. (should be further investigated).

The above could be further improved to make the TDBGrid scroll-bars adjust better:

procedure SetVisibleRows(DBGrid: TCustomDBGrid; VisibleRows: Integer);
var
  DrawInfo: TGridDrawInfo;
  TitleHeight, RowHeight: Integer;
  HasActiveDataSet: Boolean;
begin
  if VisibleRows < 0 then VisibleRows := 0;
  HasActiveDataSet := Assigned(DBGrid.DataSource) and
    Assigned(DBGrid.DataSource.DataSet) and
    DBGrid.DataSource.DataSet.Active;
  if HasActiveDataSet then
    DBGrid.DataSource.DataSet.DisableControls;
  try
    with TCustomDBGridHack(DBGrid) do
    begin
      CalcDrawInfo(DrawInfo);
      TitleHeight :=  DrawInfo.Vert.FixedBoundary;
      RowHeight := RowHeights[DrawInfo.Vert.FirstGridCell] + DrawInfo.Vert.EffectiveLineWidth;      
    end;
    DBGrid.ClientHeight := TitleHeight + (RowHeight * VisibleRows) + 1;
  finally
    if HasActiveDataSet then
      DBGrid.DataSource.DataSet.EnableControls;
  end;
end;
zig
  • 4,524
  • 1
  • 24
  • 68
  • 1
    I suggested a small edit to use `DrawInfo` instead of `RowHeights`, too. I can't say any approach is better. There might be cases where both need to take into account different heights for rows - as this is possible as I understand. That's why I thought looping the rows might be necessary. I was using a `TSpinEdit` to change the `VisibleRows` dynamically and noticed that the vertical scrollbars update was _lazy_. Only updating after selecting a row after a height change. – nil Nov 16 '17 at 11:23
  • @nil, Thanks. I have made an edit and mentioned the other option. I haven't noticed any difference though. AFAIK TDBgrid can't have variable row height. so I think its safe to rely on the first data row. I only now noticed the funky vertical scroll-bar behavior. it could be "fixed" by using the grid `DataSource.DatSet.DisableControls`/`EnableControls` (in case it has a `DataSet` attached). – zig Nov 17 '17 at 07:02
  • Thank you for editing that in, my edit was rejected. And a nice 'fix' for the scrollbars, I couldn't get behind that. – nil Nov 17 '17 at 12:06