boardtc
asked on
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.
Thanks, Tom.
? does the dbgrid not allways autosize the columns ?
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[?].DisplayWidt h with this value;
3 - Call Grid.Update
T++, Radler.
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[?].DisplayWidt
3 - Call Grid.Update
T++, Radler.
ASKER
Radler, thanks, Why would I resize the column every time in OnDrawCell?
Thanks, Tom.
Thanks, Tom.
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.
T++, Radler.
tomcorcoran :
My way is not a good idea. :-)
var
maxl:array [0..10]of integer;
implementation
{$R *.DFM}
procedure TForm1.DBGrid1DrawColumnCe ll(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
maxl[Column.Index]:=max(ma xl[Column. Index],max (length(tr im(Column. Field.asst ring))*DBG rid1.Title Font.size, length(col umn.field. DisplayNam e)*DBGrid1 .Font.size ));
Column.Width:=trunc(maxl[C olumn.Inde x]);
end;
menxin
My way is not a good idea. :-)
var
maxl:array [0..10]of integer;
implementation
{$R *.DFM}
procedure TForm1.DBGrid1DrawColumnCe
DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
maxl[Column.Index]:=max(ma
Column.Width:=trunc(maxl[C
end;
menxin
ASKER
Thnaks guys. I was hoping there was a more elegant solution. Anyone know one?
Tom.
Tom.
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.TextExten t( Str ). Cx
Grid.Fields[?].DisplayWidt h:=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.
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.TextExten
Grid.Fields[?].DisplayWidt
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.
ASKER
Radler,
Sorry for the holiday enforced delay. I tried your suggestion in OnDrawColumnCell and got an AV on the line:
Len:=Grid.Canvas.TextExten t( Str ).Cx
I couldn't figure any more info.
Cheers, Tom.
Sorry for the holiday enforced delay. I tried your suggestion in OnDrawColumnCell and got an AV on the line:
Len:=Grid.Canvas.TextExten
I couldn't figure any more info.
Cheers, Tom.
Ok a AV( Access Violation can appear ).
Tom, but the "elegant" solution ?
Was tried ?
Put this code at OnShow OK ?
T++, Radler.
Tom, but the "elegant" solution ?
Was tried ?
Put this code at OnShow OK ?
T++, Radler.
ASKER
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.
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.
T++, Radler.
ASKER
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.Field s[nIndex]) .DataSize;
FillChar(sTemp, nLen, 'X' ); //A large char
nLen := dbIndex.Canvas.TextExtent( sTemp).Cx;
dbIndex.Fields[nIndex].Dis playWidth := nLen;
end;
end;
Thanks, Tom.
procedure Tfrm.FormShow(Sender: TObject);
var
nLen, nIndex : word;
sTemp : string;
begin
for nIndex := 0 to dbIndex.FieldCount - 1 do
begin
nLen := TStringField(dbIndex.Field
FillChar(sTemp, nLen, 'X' ); //A large char
nLen := dbIndex.Canvas.TextExtent(
dbIndex.Fields[nIndex].Dis
end;
end;
Thanks, Tom.
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].Dis playWidth := nLen;
end;
end;
T++, Radler
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
SetLength( sTemp, nLen );
sTemp:=StringOfChar('X', nLen);
nLen := DBGrid1.Canvas.TextExtent(
DBGrid1.Fields[nIndex].Dis
end;
end;
T++, Radler
ASKER
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.
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(
converts it to 217.
Thanks and cheers, Tom.
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.
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.
If you remember you can calculate the length for the exibited records
DefaultDrawing:=False; //first
Table.DisableControls //second
sTemp:=Table1.Fields[nInde x].AsStrin g;
nLen := DBGrid1.Canvas.TextExtent( sTemp).Cx; //third
Table.EnableControls;
DbGrid.Invalidate; //Optional.
Not tested, waiting for reply.
T++, Radler.
DefaultDrawing:=False; //first
Table.DisableControls //second
sTemp:=Table1.Fields[nInde
nLen := DBGrid1.Canvas.TextExtent(
Table.EnableControls;
DbGrid.Invalidate; //Optional.
Not tested, waiting for reply.
T++, Radler.
ASKER
Radler, thank you. However, I am totally lost as to what you are saying but I will play around with setting DefaultDrawing.
Cheers, Tom.
Cheers, Tom.
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].Fie ldName) * 7
then
Grid.Columns[c].width := length(query.Fields[c].fie ldname) * 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(que ry.fieldde fs[c].data type) = 0
then
Multiplier := 12
else
Multiplier := 7;
if Grid.Columns[c].width < length(query.Fields[c].ass tring) * Multiplier
then
Grid.Columns[c].width := length(query.Fields[c].ass tring) * 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
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].Fie
then
Grid.Columns[c].width := length(query.Fields[c].fie
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(que
then
Multiplier := 12
else
Multiplier := 7;
if Grid.Columns[c].width < length(query.Fields[c].ass
then
Grid.Columns[c].width := length(query.Fields[c].ass
end;
query.next;
end;
query.first;
if HideFirst
then
Grid.Columns[0].width := 0;
if HideLast
then
Grid.Columns[Grid.Columns.
end;
Regards
Darren
ASKER
Radler,
It was a good attempt. Thank you. Please answer and I will grade,
Tom.
It was a good attempt. Thank you. Please answer and I will grade,
Tom.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
cheers rad man
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.
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.