2011. április 17., vasárnap

How to autosize a TDBGrid


Problem/Question/Abstract:

When placing a DBGrid on a form, it is difficult to know exactly how large it needs to be to accomodate the datafields and the number of records that are displayed. There is always a white border at the bottom under the last record and to the right of the rightmost field. There must be a simple way to tell the DBgrid (and the non data-aware grid, too) to always and automatically resize itself according to what it needs to display. Any ideas?

Answer:

Solve 1:

I use the following code to size my DBGrid and my form:

procedure TListDlg.FormCreate(Sender: TObject);
var
  W, i: Integer;
begin
  DataSet.Active := True {Make sure that your dataset is active}
  W := 0;
  for i := 0 to DBGrid.Columns.Count - 1 do
    W := W + DBGrid.Columns[i].Width + 1;
  DBGrid.ClientWidth := W;
  Self.ClientWidth := (DBGrid.Left * 2) + DBGrid.Width;
end;

Now your DBGrid is centered in your form and shows all Columns. To avoid the "white border" you can use the following code:

procedure TDBGrid.WMSize(var Msg: TWMSize);
var
  RowHeight: Integer;
  VisibleRows: Integer;
begin
  if Align <> alClient then
  begin
    if not (csDesigning in ComponentState) then
      ShowScrollBar(Handle, SB_VERT, False);
    {There is a problem in scaling a grid because the VCL includes the scrollbar}
    RowHeight := DefaultRowHeight;
    if dgRowLines in Options then
      RowHeight := RowHeight + GridLineWidth;
    VisibleRows := ClientHeight div RowHeight;
    if VisibleRows < 1 then
      VisibleRows := 1;
    if HandleAllocated then
      ClientHeight := (VisibleRows * RowHeight);
    Msg.Result := 0;
  end
  else
    inherited;
end;


Solve 2:

If you need to actually calculate the width of the entire TDBGrid, use the following:

function NewTextWidth(fntFont: TFont; const sString: OpenString): integer;
var
  fntSave: TFont;
begin
  result := 0;
  fntSave := Application.MainForm.Font;
  Application.MainForm.Font := fntFont;
  try
    result := Application.MainForm.Canvas.TextWidth(sString);
  finally
    Application.MainForm.Font := fntSave;
  end;
end;

{Calculate the width of the grid needed to exactly display with no horizontal scrollbar and with no extra space between the last column and the vertical scrollbar. The grid's datasource must be properly set and the datasource's dataset must be properly set, though it need not be open. Note: this width includes the width of the vertical scrollbar, which changes based on screen resolution. These changes are compensated for.}

function iCalcGridWidth(dbg: TDBGrid): integer;
const
  cMEASURE_CHAR = '0';
  iEXTRA_COL_PIX = 4;
  iINDICATOR_WIDE = 11;
var
  i, iColumns, iColWidth, iTitleWidth, iCharWidth: integer;
begin
  iColumns := 0;
  result := GetSystemMetrics(SM_CXVSCROLL);
  iCharWidth := NewTextWidth(dbg.Font, cMEASURE_CHAR);
  with dbg.dataSource.dataSet do
    for i := 0 to FieldCount - 1 do
      with Fields[i] do
        if visible then
        begin
          iColWidth := iCharWidth * DisplayWidth;
          if dgTitles in dbg.Options then
          begin
            iTitleWidth := NewTextWidth(dbg.TitleFont, DisplayLabel);
            if iColWidth < iTitleWidth then
              iColWidth := iTitleWidth;
          end;
          inc(iColumns, 1);
          inc(result, iColWidth + iEXTRA_COL_PIX);
        end;
  if dgIndicator in dbg.Options then
  begin
    inc(iColumns, 1);
    inc(result, iINDICATOR_WIDE);
  end;
  if dgColLines in dbg.Options then
    inc(result, iColumns)
  else
    inc(result, 1);
end;

I had to use the function NewTextWidth, rather than the Grid's Canvas.TextWith as the Canvas of the Grid may not initialized when you need to call iCalcGridWidth.

Nincsenek megjegyzések:

Megjegyzés küldése