database 如何根据其内容自动调整/缩放 DBGrid(或其他类似)的列宽?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13292937/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to auto fit/scale DBGrid's (or other similar) columns widths according to its contents?
提问by Please_Dont_Bully_Me_SO_Lords
I am trying to make a frame with a DBGridthat will serve for more than 10 tables with half of its fields as defaults, and other fields exclusive for each table.
我正在尝试制作一个框架,该框架DBGrid将服务于 10 个以上的表,其中一半的字段作为默认值,而其他字段则是每个表独有的。
As the space for the columns are limited and I do not want to configure each column of each table manually because it is very poor quality work, I was wondering a way to calculate the width of each column by the largest content of a row inside that column, measured by the own component or by the data set.
由于列的空间有限,我不想手动配置每个表的每一列,因为它的工作质量很差,我想知道一种通过其中一行的最大内容来计算每列宽度的方法列,由自己的组件或数据集测量。
Does anyone knows the way? Is there out in the world some custom component with that power? I need a solution that implements increase and decrease of size, according to the the visible data in the all visible columns of the grid.My solution so far had a problem with the painting of the selected cell, witch jumps out of the selected dataset row.
有人知道路吗?世界上是否有一些具有这种能力的自定义组件? 我需要一个解决方案,根据网格的所有可见列中的可见数据实现大小的增加和减少。到目前为止,我的解决方案在选定单元格的绘制方面存在问题,女巫跳出选定的数据集行。


Note: Please, do not close my question. It is not about the fit with the grid's width or the form's width. It is about all the columns width to minimize the horizontal scrollbar, but not necessarily hide it.
注意:请不要关闭我的问题。这与网格宽度或表单宽度的匹配无关。它是关于最小化水平滚动条的所有列宽,但不一定隐藏它。
回答by alzaimar
What you have to do is to use the grid's canvas to measure the contents of each column and set the column's width accordingly. You can either iterate through the dataset or use the OnColumnDraw-Event to adjust the width on the fly.
您需要做的是使用网格的画布来测量每列的内容并相应地设置列的宽度。您可以遍历数据集或使用 OnColumnDraw-Event 动态调整宽度。
Here's a sample (I had to use an offset of 5 pixels)
这是一个示例(我必须使用 5 个像素的偏移量)
procedure TForm7.DBGridDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
Var
  w : Integer;
begin
  w := 5+DBGrid.Canvas.TextExtent(Column.Field.DisplayText).cx;
  if w>column.Width then Column.Width := w;
end;
procedure TForm7.FormActivate(Sender: TObject);
Var
  i : Integer;
begin
  // Initialize width
  for I := 0 to DBGrid.Columns.Count - 1 do
    DBGrid.Columns[i].Width := 5 + DBGrid.Canvas.TextWidth(DBGrid.Columns[i].title.caption)
end;
回答by Cesar Romero
EDITED:
编辑:
My first code was about fit the columns inside the grid with, with this new code, AutoSizeColumns reads the records to calc the width of each column until MaxRows or Dataset.Eof:
我的第一个代码是关于用这个新代码拟合网格内的列,AutoSizeColumns 读取记录以计算每列的宽度,直到 MaxRows 或 Dataset.Eof:
class function TDBGridHelper.AutoSizeColumns(DBGrid: TDBGrid; const MaxRows: Integer = 25): Integer;
var
  DataSet: TDataSet;
  Bookmark: TBookmark;
  Count, I: Integer;
  ColumnsWidth: array of Integer;
begin
  SetLength(ColumnsWidth, DBGrid.Columns.Count);
  for I := 0 to DBGrid.Columns.Count - 1 do
    if DBGrid.Columns[I].Visible then
      ColumnsWidth[I] := DBGrid.Canvas.TextWidth(DBGrid.Columns[I].Title.Caption + '   ')
    else
      ColumnsWidth[I] := 0;
  if DBGrid.DataSource <> nil then
    DataSet := DBGrid.DataSource.DataSet
  else
    DataSet := nil;
  if (DataSet <> nil) and DataSet.Active then
  begin
    Bookmark := DataSet.GetBookmark;
    DataSet.DisableControls;
    try
      Count := 0;
      DataSet.First;
      while not DataSet.Eof and (Count < MaxRows) do
      begin
        for I := 0 to DBGrid.Columns.Count - 1 do
          if DBGrid.Columns[I].Visible then
            ColumnsWidth[I] := Max(ColumnsWidth[I], DBGrid.Canvas.TextWidth(
              DBGrid.Columns[I].Field.Text));
        Inc(Count);
        DataSet.Next;
      end;
    finally
      DataSet.GotoBookmark(Bookmark);
      DataSet.FreeBookmark(Bookmark);
      DataSet.EnableControls;
    end;
  end;
  Count := 0;
  for I := 0 to DBGrid.Columns.Count - 1 do
    if DBGrid.Columns[I].Visible then
    begin
      DBGrid.Columns[I].Width := ColumnsWidth[I];
      Inc(Count, ColumnsWidth[I]);
    end;
  Result := Count - DBGrid.ClientWidth;
end;
I call it in the DataSet.AfterOpen event:
我在 DataSet.AfterOpen 事件中调用它:
TGridHelper.AutoSizeColumns(MyDBGrid);
回答by sarram
Why to use so complicated code? :D Just use this. Its also have 5 px offset.
为什么要用这么复杂的代码?:D 就用这个。它也有 5 px 偏移。
procedure TForm1.FormActivate(Sender: TObject);
var
  i:integer;
begin
  for i :=0 to DbGrid1.Columns.Count - 1 do
   DbGrid1.Columns[i].width :=5+dbgrid1.Canvas.TextWidth(DbGrid1.Columns[i].Title.Caption);
end;
回答by jacques
For each column you want to be auto sized set the property SizePriority=1and for fixed columns set SizePriority=0, in your case only the last column will be auto sized.
对于您想要自动调整大小的每一列,设置属性SizePriority=1并为固定列设置SizePriority=0,在您的情况下,只有最后一列会自动调整大小。
Then set property grid.AutoFillColumns=trueand that should do it.
然后设置属性grid.AutoFillColumns=true,应该这样做。
回答by R.Alonso
For TRUEDBGRID .net you can do this:
对于 TRUEDBGRID .net 你可以这样做:
 Private Sub AutoSizeGrid(Grid As C1.Win.C1TrueDBGrid.C1TrueDBGrid)
        For Each Sp As C1.Win.C1TrueDBGrid.Split In Grid.Splits
            For Each Cl As C1.Win.C1TrueDBGrid.C1DisplayColumn In Sp.DisplayColumns
                Cl.AutoSize()
            Next
        Next
End Sub
For TrueDbGrid ActiveX in vb60 this (this code not include splits):
对于 vb60 中的 TrueDbGrid ActiveX(此代码不包括拆分):
Public Function APEXGridAutoFix(Grid As TrueOleDBGrid80.TDBGrid)
Dim Col As TrueOleDBGrid80.Column
For Each Col In Grid.Columns
    Col.AutoSize
Next
End Function
回答by Please_Dont_Bully_Me_SO_Lords
This solution makes all columns expand or shrink according to it's contents, without care if there has to be scroll bars or not, and fix the selected cell drawing malfunction and the the record pointer malfunction.
该解决方案使所有列根据其内容进行扩展或收缩,而无需考虑是否有滚动条,并修复了选定单元格绘制故障和记录指针故障。
type
  TColumnAutoAdjust = record {Save the information responsible for setting column widths in the grid}
    Field: String;           {Field name whose information is being stored}
    Registered: Boolean;     {Indicates whether the size of this column already registered}
    Updated: Boolean;        {Indicates the actual size of the column was updated}
    LastWidth: Integer;      {Width indicates the final text of a record of a row column}
    CurrWidth: Integer;      {Indicates the current size and column width}
    Reverter: Integer;       {Indicates the greatest width recorded but that is less than the current}
    Scrolls: Integer;        {Indicates the amount of scrolls present after one width adjustment}
    RecNo: Integer;          {Indicates which was the record in the table which increased the width of colune}
  end;
var { inside the forms private }
  gdCols: array of TColumnAutoAdjust; { vetor de ajuste de largura de cada coluna na grade de resultado }
  RegisteredCols: Integer; { quantas colunas já foram registradas no controle de ajuste }
  gdVisibleRows: Integer; { quantas linhas de cadastros est?o visíveis da grade de resultado }
  gdVisibleCols: Integer; { quantas colunas de cadastros est?o visíveis da grade de resultado }
{ before showing the grid }  
    RegisteredCols := ResultGrid.Columns.Count;
    SetLength(gdCols, RegisteredCols); { determina o tamanho da vetor de controle de colunas }
    { libera a lista }
    ResultGrid.Align := alClient;
    for i := 0 to RegisteredCols -1 do { inicializando a largura das colunas no tamanho do título de cada }
    begin
      gdCols[i].Field := ResultGrid.Columns[i].FieldName;
      ResultGrid.Columns[i].Width := ResultGrid.Canvas.TextExtent(ResultGrid.Columns[i].Title.Caption).cx;
      ResultGrid.Columns[i].Alignment := taLeftJustify;
      ResultGrid.Columns[i].Title.Alignment := taLeftJustify;
    end;
    BrowserQuery.Open;
    ResultGrid.Show;
    for i := 0 to gdVisibleRows do
    begin
      BrowserQuery.Next;
      ResultGrid.Refresh;
    end;
    for i := 0 to gdVisibleRows do
    begin
      BrowserQuery.Prior;
      ResultGrid.Refresh;
    end;
    BrowserQuery.First;
    ResultGrid.SetFocus;
  end
{ after dataset scroll}      
procedure TRecordsBrowserFrameBase.BrowserQueryAfterScroll(DataSet: TDataSet);
var
  i, TitleWidth: Integer;
  mayAdjustAgain: Boolean; {  }
begin
{ ajusta as colunas da grade de resultado a cada movimento da tabela de resultado }
  mayAdjustAgain := False;
  for i := 0 to RegisteredCols -1 do
  begin
    if not gdCols[i].Updated then
    begin
      ResultGrid.Columns[i].Width := gdCols[i].CurrWidth;
      gdCols[i].Scrolls := 0;
      gdCols[i].Updated := True;
    end
    else
    begin
      Inc(gdCols[i].Scrolls);
      if (DataSet.RecNo > gdCols[i].RecNo + gdVisibleRows) or (DataSet.RecNo < gdCols[i].RecNo - gdVisibleRows) then
      begin
        TitleWidth := MaxColSpacing + ResultGrid.Canvas.TextExtent(ResultGrid.Columns[i].Title.Caption).cx;
        gdCols[i].LastWidth := gdCols[i].CurrWidth;
        gdCols[i].CurrWidth := IFX(gdCols[i].Reverter > TitleWidth, gdCols[i].Reverter, TitleWidth);
        gdCols[i].Reverter := IFX(gdCols[i].Reverter > TitleWidth, TitleWidth, 0);
        gdCols[i].Updated := False;
        mayAdjustAgain := True;
      end;
    end;
  end;
  if mayAdjustAgain then
  begin
    ResultGrid.Refresh;
    BrowserQueryAfterScroll(DataSet);
  end;
end;
{ on draw column cell }
procedure TRecordsBrowserFrameBase.GridColumnWidthAdjust(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  ColWidth, TextWidth, TitleWidth: Integer;
begin
{ ajusta a capitaliza??o do texto das células }
  (Sender as TJvDBGrid).Canvas.Pen.Color := clWhite;
  (Sender as TJvDBGrid).Canvas.Rectangle(Rect);
  (Sender as TJvDBGrid).Canvas.TextOut(Rect.Left+2, Rect.Top+2, NameCase(Column.Field.DisplayText));
{ ajusta as colunas de uma grade de acordo com o conteúdo das células }
  gdVisibleRows := (Sender as TJvDBGrid).VisibleRowCount;
  gdVisibleCols := (Sender as TJvDBGrid).VisibleColCount;
  TitleWidth := MaxColSpacing + (Sender as TJvDBGrid).Canvas.TextExtent(Column.Title.Caption).cx;
  TextWidth := MaxColSpacing + (Sender as TJvDBGrid).Canvas.TextExtent(NameCase(Column.Field.DisplayText)).cx;
  ColWidth := Column.Width;
  {$WARNINGS OFF}
  if (TextWidth > gdCols[DataCol].Reverter) and (TextWidth < ColWidth) then gdCols[DataCol].Reverter := TextWidth;
  if (TextWidth > ColWidth) then { texto da célula é mais largo que a coluna }
  begin
    gdCols[DataCol].Registered := True;
    gdCols[DataCol].LastWidth := ColWidth;
    gdCols[DataCol].CurrWidth := TextWidth;
    gdCols[DataCol].Updated := False;
    gdCols[DataCol].RecNo := BrowserQuery.RecNo;
    gdCols[DataCol].Reverter := TitleWidth;
    Exit;
  end;
  if (ColWidth < TitleWidth) then { texto da célula é menor que o título da coluna }
  begin
    gdCols[DataCol].Registered := True;
    gdCols[DataCol].LastWidth := ColWidth;
    gdCols[DataCol].CurrWidth := TitleWidth;
    gdCols[DataCol].Updated := False;
    gdCols[DataCol].Reverter := TitleWidth;
    Exit;
  end;
{$WARNINGS ON}
end;
回答by H Hicham
Hello use this procedure.
你好用这个程序。
Procedure AutoSizeColDBGrid(DBGrid:TDBGrid);
var i, ColWidth, ColTextWidth:integer;
begin
 if DBGrid.DataSource.DataSet.Active then
   begin
     DBGrid.DataSource.DataSet.DisableControls;
     for i:= 0 to DBGrid.Columns.Count-1 do
       begin
         ColWidth:=DBGrid.Canvas.TextWidth(DBGrid.Columns[i].Field.DisplayLabel);
         DBGrid.DataSource.DataSet.First;
       while not DBGrid.DataSource.DataSet.EOF do
        begin
       ColTextWidth:=DBGrid.Canvas.TextWidth(DBGrid.Columns[i].Field.DisplayText);
          if (ColTextWidth > ColWidth) then
            begin
              ColWidth := ColTextWidth;
            end;
          DBGrid.DataSource.DataSet.Next;
       end;{while}
       DBGrid.Columns[i].Width:=ColWidth+10;
     end;{for}
DBGrid.DataSource.DataSet.EnableControls;
DBGrid.DataSource.DataSet.First;
end;
end;
回答by Carsten
Use procedure DbGrid1.AutoAdjustColumnsand that's it.
使用程序DbGrid1.AutoAdjustColumns,就是这样。

