Question

Let's say I have this table:

name        varchar(255),
quantity    integer,
value       float

When I used this code:

select left(name, 99), quantity, value from table;

But I've got all the 255 spaces (by space I mean width length, not the real space chars) on the first column of the dbgrid and the other two fields where away unless I used the scroll bar and my objective was to make scroll bars not necessary.

How do I get this goal correctly? I use Firebird and MySQL.

I can not do this by pascal code nor define it on the Fields object of the table component because this codes comes from many tables as this is a report generator and the first field is not always the same and for each report I have to use a different SQL code.

enter image description here

PLEASE, EVERYBODY READ THE ALL QUESTION BEFORE ANSWERING. THE FIRST 3 ANSWER WHERE WRONG BECAUSE THEY DID NOT CONSIDERED WHAT AS WRITTEN IN THE LAST PARAGRAPH!

Was it helpful?

Solution

Since you've said you can't do it on the TField level or in your Delphi code, you can use Trim() or Left(), depending on the database you're using, on the column to remove the blank spaces you don't want to display:

For instance, in many SQL dialects you could use something like:

SELECT Col1, Col2, Trim(Col3) as Col3 FROM yourtable 
WHERE somecondition

Some allow this instead:

SELECT Col1, Col2, Left(Col3, MaxCharWidthAllowed) as Col3 FROM yourtable 
WHERE somecondition

or

SELECT Col1, Col2, Substring(Col3, 1, MaxCharWidth) as Col3 FROM yourtable

As a quick test (I don't have FB, but have SQL Server 2008, so I used it), I created the following test data in SQL Server Management Studio:

Test data in SSMS

I then created a new D2007 VCL Forms application, and performed the following steps:

  • Dropped an TADOConnection on the form (ADOConnection1), and set up the connection string to the test data above
  • Dropped two TADOQuery components on the form (ADOQuery1 and ADOQuery2), and set their Connection properties to ADOConnection1
  • Dropped two TDataSource components on the form (DataSource1 and DataSource2) and connected their DataSet properties to the matching ADOQuery1 and ADOQuery2
  • Dropped two TDBGrid components (DBGrid1 and DBGrid2) and set their DataSource properties to the matching DataSource1 and DataSource2.
  • Added SELECT * FROM test to the SQL for ADOQuery1
  • Added SELECT Substring(itemname, 1, 30) as itemname, quantity, value FROM test as the SQL of ADOQuery2. The length of 30 was arbitrarily chosen as being a small enough value to demonstrate the considerably smaller column width.
  • Set ADOConnection1.Connected to True, and set both TADOQuery.Active properties to True.

The above produced this output (at design time, without ever compiling or running the application), with the top grid being DBGrid1:

Design-time output of above steps

As you can see, in DBGrid2, which is connected to ADOQuery2 with the Substring in the SQL, the first column is correctly sized to 30 characters width.

OTHER TIPS

If the column type is really varchar(255) and not char(255) then there shouldn't be any spaces in the end of the value unless you saved the spaces yourself. IOW the varchar(255) values will be returned to you exactly as you saved them into the table whether char(255) values will be right padded with spaces so that you always get string with 255 characters.

Thus I'd say that if you use varchar type and you don't pad the values with spaces when saving them into the DB then the problem is really in the grid and you can't solve it usimg trim() or equivalent in SQL. Most likely the grid reads the field's definition, sees that the max length of the value is 255 characters and sets the column width accordingly. So the solution is really to set the column width manually or use column's ApplyBestFit method (if it has one).

There are two ways of limiting the length of a field displayed in a DBGrid that do not alter the data from the database. One is by setting the DisplayWidth of the field and the other is setting the Width of the grid column.

You can set the DisplayWidth in the After open event of the query. The example is for ZeosLib and assumes the first field is the one to be limited. This would need to be added to each Query.

procedure TForm1.ZQuery1AfterOpen(DataSet: TDataSet);
begin
  DataSet.Fields[0].DisplayWidth := 99;
end;

or use a procedure to set the DBGrid Column Width after the query is opened. This example lets you specify the column as well as the width.

procedure TForm1.SetColWidth(c,w: integer);
begin
  if DBGrid1.Columns.Count > c then
    DBGrid1.Columns[c].Width := w;
end;

Update:

Delphi takes as default for Displaylength the length of the varchar field. varchar(255) = Displaylength = 255.

Can I change this behavior with "SQL". NO If the result is only 99 characters long, the length varchar (255) = 255 and Displaylength = 255 .

Compare it!
allowed:

select left(name,99), quantity, value from table;
  • Sql should quickly deliver a dataset (not the design of a report).
  • For each table for each varchar field, you have to set an extra SQL statement (xname,99)
  • Can I see, truncated (perhaps important) information? Never.

wy not allowed:

Columns[index].Width = 99;
  • Easier to design a report.
  • Easier select SQL statement: select name, quantity, value from table
  • Simple expand column with mouse to see hidden information.
  • Good Design: The column size of a DBGrid should be that you can see at least 2 columns at once.

The program should take over the design.

I can not do this by pascal code nor define it on the Fields object of the table component because this code comes from many tables as this is a report generator.

and for each report I have to use a different SQL code.

Who generates this "different SQL code"?
I think similar lines are used to generate the code (Pascal code).

Allowed: Pascal code

   Query1.Close;
   Query1.SQL.Clear;
   Query1.SQL.Add ('select name, quantity, value from table');
   Query1.Active: = true;

why not allowed: Pascal code

   Columns[index].Width := 99;

you can do it with an automatic adjustment of the columns. All columns wider a certain size are to be adapted to their actual width. That's still better than a fixed size = 99.

The following program has been tested with Rad Studio 2007 and Zeos Components.
Firebird 2.5, on a Windows 2000 computer.

  • A) Zeos Components.
  • B) DBGrid1 no active data connection.
  • C) Firebird automatically allocated size for varchar (255).
  • D) The running Program. "use Me" is used to automatically size the column.

For lack of time, I created only 2 data fields.

enter image description here

If the entire source code is required for download, let me know.

unit FBAuto;
{
~Zarko Gajic
About Delphi Programing
http://delphi.about.com
customized 2013
moskito-x software
}

interface

uses
  Math,
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, DBTables, Grids, DBGrids, ExtCtrls, StdCtrls, ZAbstractRODataset,
  ZAbstractDataset, ZDataset, ZConnection;

type
  TAutoColumnWidth = record
    Index : integer;
    Width : integer;
  end;

  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    ZConnection1: TZConnection;
    ZQuery1: TZQuery;
    DataSource1: TDataSource;
    CBuseMe: TCheckBox;
    DBGrid2: TDBGrid;
    ZQuery2: TZQuery;
    DataSource2: TDataSource;
    IntegerField1: TIntegerField;
    StringField1: TStringField;
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure CBuseMeClick(Sender: TObject);
  private
    { Private declarations }
    procedure SetFit;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  AutoColumnWidth : TAutoColumnWidth;
  useMe :Boolean;

procedure TForm1.SetFit;
var
  i:integer;
begin
  if NOT CBuseMe.Checked then begin
  for i := 0 to DBGrid1.Columns.Count - 1 do begin
     if DBGrid1.Columns[i].Field.Size > 300 then
        DBGrid1.Columns[i].Width := DBGrid1.Columns[i].Field.Size;
  end;
  end else begin
  useMe:=true;
  for i := 0 to DBGrid1.Columns.Count - 1 do begin
  AutoColumnWidth.Index:=-1;
  if DBGrid1.Columns[i].Field.DisplayWidth > 200 then  AutoColumnWidth.Index:=i;
     if AutoColumnWidth.Index > -1 then begin
        AutoColumnWidth.Width := -1;
        DBGrid1.Repaint;
        DBGrid1.Columns[AutoColumnWidth.Index].Width := AutoColumnWidth.Width+ 5;
     end;
  end;
  useMe:=false;
  end;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
ZQuery1.Active:=true;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  AutoColumnWidth.Index := -1;
  AutoColumnWidth.Width := -1;
  useMe:=false;
end;

procedure TForm1.CBuseMeClick(Sender: TObject);
begin
  setFit;
end;

procedure TForm1.DBGrid1DrawColumnCell(
  Sender: TObject;
  const Rect: TRect;
  DataCol: Integer;
  Column: TColumn;
  State: TGridDrawState);
begin
  if useMe then begin
   if DataCol = AutoColumnWidth.Index then
   begin
    if Assigned(Column.Field) then
    begin
      AutoColumnWidth.Width := Max(AutoColumnWidth.Width, DBGrid1.Canvas.TextWidth(Column.Field.DisplayText));
    end;
   end;
  end;
end;

end.

> 200 to adapt it to your needs can be set.

if DBGrid1.Columns[i].Field.DisplayWidth > 200 then  AutoColumnWidth.Index:=i;

I hope this helps a little, or may lead into the right direction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top