4
votes

I've got a TDBGrid with predefined columns, and I just can't get the width right. I can mess with the Width property of the columns in the Form Designer and get the width to look just right at design time, but at runtime, for whatever reason, the columns tend to be significantly wider, and I end up with a scroll bar at the bottom of the grid. Is there any way to get make the columns size themselves correctly without all the trial-and-error, especially if the grid only has one or two of them?

5
Since I have the same problem with Lazarus I don't think this is a bug. Any way JP's answer has worked for me :)itsols
An observation: I had a TDBGrid on an ancestor form and a descendant form that inherited from that form. The column were set in the ancestor. I had the same problem with the run time widths being wrong. I noticed that the descendant form reasserted some but not all of the columns of the ancestor (looking at the DFM). I deleted those columns from the DFM of the descendant. That seems to show all the columns (which is what I wanted anyway). After that, the run-time-widths were correct.dan-gph

5 Answers

4
votes

I use this procedure inside forms OnResize event

procedure AutoStretchDBGridColumns(Grid: TDBGrid; Columns, MinWidths: Array of integer);
var
  x, i, ww: integer;
begin
  // Stretches TDBGrid columns
  // Columns contains columns to stretch
  // MinWidths contains columns minimum widhts
  // To stretch grids columns 1,2 and 5 automatically and set minimum widths to 80, 150 and 150 call
  // AutoStretchDBGridColumns(DBGrid1, [1,2,5], [80, 150, 150]);
  Assert(Length(Columns) = Length(MinWidths), 'Length(Columns) <> Length(MinWidths)');
  ww := 0;
  for i := 0 to Grid.Columns.Count - 1 do
  begin
    if Grid.Columns[i].Visible then
      ww := ww + Grid.Columns[i].Width + 1; //** +1 for grid line width
  end;
  if dgIndicator in Grid.Options then
    ww := ww + IndicatorWidth;
  x := (Grid.ClientWidth - ww) div Length(Columns);
  for i := 0 to  High(Columns) do
    Grid.Columns[Columns[i]].Width := Max(Grid.Columns[Columns[i]].Width + x, MinWidths[i]);
end;

It has some flaws, but works quite well.

1
votes

I think I know the answer to the problem. I had the same problem for a few years. When I put demo data in I resize the columns width (design time) but I suspect, as a bug in Delphi, if the width you enter is the same as the default width Delphi assigns to the column, the width is not saved in the dfm file - as can be seen if you view the dfm as text.

My solution is to set it to one pixel wider or narrower so that Delphi will be forced to store the width (or edit the dfm directly) and so it will be set at run time. If you don't set it, Delphi will assign some calculated width at run time - which is not what you want as it could change depending on the data. Simple solution but it took me a long time to figure out.

0
votes

You can do that, but you have to check the width of all fields for all records that you potentially can display.

Given the fact that there are still plenty of applications that hardly filter their record set, this can mean that you need to check a zillion records, just to get rid of the scrollbar.

Have you ever considered that you might just want to display too much information at once?

A possible alternative is to show a hint text for fields that do not fit in their column?

I have used such an alternative, but need to check the sources; I can get you some sample code tomorrow.

--jeroen

0
votes

JP's answer is a pretty good solution. You need to manually stretch or shrink the columns as necessary to make it fit in the window. There is a windows API call to get the vertical scroll bar width. Then you can look at the visible rows to see if the vertical scroll bar is being shown.

Another technique is to figure out the width of each column relative to each other. Then when you resize them maintain the same ratio.

0
votes

You may have a look at the answers to this question.

Perhaps the protected CalcDrawInfo method may help here.