[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1173
  • Last Modified:

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.
0
boardtc
Asked:
boardtc
1 Solution
 
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 your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
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
 
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

Featured Post

Take Control of Web Hosting For Your Clients

As a web developer or IT admin, successfully managing multiple client accounts can be challenging. In this webinar we will look at the tools provided by Media Temple and Plesk to make managing your clients’ hosting easier.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now