Autosize TDbGrid columns

Hi, I am running D C/S 4.03. I am wondering if there is a way to autosize the columns in a TDbGrid, I would like the initial size to be as wide as the column name or the largest data in the column. Any suggestions would be appreciated.

Thanks, Tom.
boardtcAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

kretzschmarCommented:
? does the dbgrid not allways autosize the columns ?
0
RadlerCommented:
I hate my proper comments, because they aren't the complete solution. Well, let's go:
All steps will done at OnDrawcell
1 - Measure the length necessary to draw the field content without clipping
1.1 - Use TCanvas.TextExtent( field.Content.AsString ...).Cx
2 - Set the Grid.Fields[?].DisplayWidth with this value;
3 - Call Grid.Update

T++, Radler.
0
boardtcAuthor Commented:
Radler, thanks, Why would I resize the column every time in OnDrawCell?

Thanks, Tom.
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

RadlerCommented:
Only a part of all records are loaded by moment. So supposing that the first 40 records have a length 100 and the rest 120 a trunc would be done.

T++, Radler.
0
men xinCEOCommented:
tomcorcoran :

My way is not a good idea.  :-)


var
  maxl:array [0..10]of integer;

implementation

{$R *.DFM}

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  maxl[Column.Index]:=max(maxl[Column.Index],max(length(trim(Column.Field.asstring))*DBGrid1.TitleFont.size,length(column.field.DisplayName)*DBGrid1.Font.size));
  Column.Width:=trunc(maxl[Column.Index]);
end;

menxin
0
boardtcAuthor Commented:
Thnaks guys. I was hoping there was a more elegant solution. Anyone know one?

Tom.
0
RadlerCommented:
Elegant solution ?
Well, let's go:
Supposing a TStringField, to others field types, like Numeric/date the size is what you desire

var
Len : word;
Str : string;
begin
Len:=TStringField( Grid.Fields[?] ).DataSize;
FillChar( Str, Len, 'X' ); //A large char
Len:=Grid.Canvas.TextExtent( Str ). Cx
Grid.Fields[?].DisplayWidth:=Len;
end;

Put this code segment at a location before user view the data, like OnShow by Example.
It's the more optmizated solution.

T++, Radler.
0
boardtcAuthor Commented:
Radler,

Sorry for the holiday enforced delay. I tried your suggestion in OnDrawColumnCell and got an AV on the line:

Len:=Grid.Canvas.TextExtent( Str ).Cx

I couldn't figure any more info.

Cheers, Tom.
 
0
RadlerCommented:
Ok a AV( Access Violation can appear ).
Tom, but the "elegant" solution ?
Was tried ?
Put this code at OnShow OK ?

T++, Radler.
0
boardtcAuthor Commented:
I tried the elegant soilution in OnDrawColumnCell. In OnShow, are you suggesting a for loop on the fieldcount to acecss the fields array? Anyway I tried that and get a AV in the same place. Thanks, Tom.
0
RadlerCommented:
Seems that I need make a sample code to you. My time is short now, at next week I'm more availble. Wait a bit, sorry, is my astral hell.

T++, Radler.
0
boardtcAuthor Commented:
Thanks, I'm afraid your solution did not work:

procedure Tfrm.FormShow(Sender: TObject);
var
  nLen, nIndex : word;
  sTemp : string;
begin
  for nIndex := 0 to dbIndex.FieldCount - 1 do
  begin
    nLen := TStringField(dbIndex.Fields[nIndex]).DataSize;
    FillChar(sTemp, nLen, 'X' ); //A large char
    nLen := dbIndex.Canvas.TextExtent(sTemp).Cx;
    dbIndex.Fields[nIndex].DisplayWidth := nLen;
  end;
end;

Thanks, Tom.
0
RadlerCommented:
Hi, I back soon.
I tested this and is OK. The visual result will depend of fields length and maybe very large at some situations.


procedure TForm1.FormShow(Sender: TObject);
var
  nLen, nIndex : word;
  sTemp : string;
begin
      for nIndex := 0 to Table1.FieldCount-1 do begin
            nLen := TStringField(Table1.Fields[nIndex]).DataSize;
            SetLength( sTemp, nLen );
            sTemp:=StringOfChar('X', nLen);
            nLen := DBGrid1.Canvas.TextExtent(sTemp).Cx;
            DBGrid1.Fields[nIndex].DisplayWidth := nLen;
      end;
end;

T++, Radler
0
boardtcAuthor Commented:
Radler,

Makes sense, SetLength instead of FillChar. It does not crash now, but results in masively wide columns, for instance the first one is wider than my screen. What happens is that nLen is 31 but

nLen := DBGrid1.Canvas.TextExtent(sTemp).Cx;

converts it to 217.

Thanks and cheers, Tom.
0
RadlerCommented:
Tom, was what I said. You need calc the column length at dispaly time to avoid larger columns. Or smaller fields datasizes comparing with the real data stored.
Well supposing that you designed your DB the choice is your. I prefer at OnDraw? events.
An alternative is OnTitleClick ( more user interface elegant ).
Have a nice work/day.

T++, Radler.
0
RadlerCommented:
If you remember you can calculate the length for the exibited records
DefaultDrawing:=False; //first

Table.DisableControls //second

sTemp:=Table1.Fields[nIndex].AsString;
nLen := DBGrid1.Canvas.TextExtent(sTemp).Cx; //third

Table.EnableControls;

DbGrid.Invalidate; //Optional.

Not tested, waiting for reply.

T++, Radler.
0
boardtcAuthor Commented:
Radler, thank you. However, I am totally lost as to what you are saying but I will play around with setting DefaultDrawing.
Cheers, Tom.
0
dhnkleyCommented:
I use the following to auto size all my grids in app, not real flash but does the job.

Procedure TdmData.AutoSizeGrid(Grid : TDBGrid; Query : TQuery;
                               HideFirst, HideLast : boolean);
var
  c,r : integer;
  Multiplier : integer;
begin
  for c := 0 to Grid.Columns.Count - 1
  do
  begin
    Grid.columns[c].width := 50;  //minimum
    if 50 < length(query.Fields[c].FieldName) * 7
    then
      Grid.Columns[c].width := length(query.Fields[c].fieldname) * 7;
  end;
  query.First;
  for r := 0 to query.recordCount - 1
  do
  begin
    for c := 0 to Grid.Columns.Count - 1
    do
    begin
      if frmSearch.getfieldtype(query.fielddefs[c].datatype) = 0
      then
        Multiplier := 12
      else
        Multiplier := 7;
      if Grid.Columns[c].width < length(query.Fields[c].asstring) * Multiplier
      then
        Grid.Columns[c].width := length(query.Fields[c].asstring) * Multiplier;
    end;

    query.next;

  end;

  query.first;

  if HideFirst
  then
    Grid.Columns[0].width := 0;

  if HideLast
  then
    Grid.Columns[Grid.Columns.Count - 1].width := 0;

end;


Regards
Darren
0
boardtcAuthor Commented:
Radler,

It was a good attempt. Thank you. Please answer and I will grade,

Tom.
0
RadlerCommented:
Hi Tom,

I provided the best imediate solution, but seems that results are insastifactory, and I dont wanna this.
But it's all that can make by momment.

T++, Radler.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
boardtcAuthor Commented:
cheers rad man
0
RadlerCommented:
Thanks Tom.
The dhnkley's code give a idea now. At future you can put a call to my code only to response a user click at column header to resize the next/previous viewed records.
Thanks again.

T++, Radler.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.