2011. április 17., vasárnap

How to autosize a TDBGrid


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?


Solve 1:

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

procedure TListDlg.FormCreate(Sender: TObject);
  W, i: Integer;
  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;

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);
  RowHeight: Integer;
  VisibleRows: Integer;
  if Align <> alClient then
    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;

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;
  fntSave: TFont;
  result := 0;
  fntSave := Application.MainForm.Font;
  Application.MainForm.Font := fntFont;
    result := Application.MainForm.Canvas.TextWidth(sString);
    Application.MainForm.Font := fntSave;

{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;
  cMEASURE_CHAR = '0';
  i, iColumns, iColWidth, iTitleWidth, iCharWidth: integer;
  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
          iColWidth := iCharWidth * DisplayWidth;
          if dgTitles in dbg.Options then
            iTitleWidth := NewTextWidth(dbg.TitleFont, DisplayLabel);
            if iColWidth < iTitleWidth then
              iColWidth := iTitleWidth;
          inc(iColumns, 1);
          inc(result, iColWidth + iEXTRA_COL_PIX);
  if dgIndicator in dbg.Options then
    inc(iColumns, 1);
    inc(result, iINDICATOR_WIDE);
  if dgColLines in dbg.Options then
    inc(result, iColumns)
    inc(result, 1);

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