【问题标题】:How to auto fit/scale DBGrid's (or other similar) columns widths according to its contents?如何根据其内容自动调整/缩放 DBGrid 的(或其他类似的)列宽?
【发布时间】:2012-11-08 16:10:54
【问题描述】:

我正在尝试使用 DBGrid 制作一个框架,它将为 10 多个表提供服务,其中一半字段作为默认值,其他字段为每个表所独有。

由于列的空间是有限的,我不想手动配置每个表的每一列,因为它的质量很差,我想知道一种方法可以通过一个最大的内容来计算每列的宽度该列内的行,由自己的组件或数据集测量。

有人知道路吗?世界上是否有一些具有这种能力的定制组件? 我需要一个解决方案,根据网格所有可见列中的可见数据来实现大小的增加和减少。 到目前为止,我的解决方案在选定单元格的绘制方面存在问题,女巫跳出选定的数据集行。


注意:请不要关闭我的问题。这与网格宽度或表单宽度无关。将水平滚动条最小化是所有列的宽度,但不一定要隐藏它。

【问题讨论】:

  • @RRUZ 它不适合表单,而是适合自己的内容,即使水平滚动条可见。
  • 我知道我以前问过这个问题并得到了很好的答案...
  • @kobik 链接已失效。

标签: database delphi delphi-2006 tdbgrid


【解决方案1】:

您要做的是使用网格的画布来测量每一列的内容并相应地设置列的宽度。您可以遍历数据集或使用 OnColumnDraw-Event 动态调整宽度。

这是一个示例(我必须使用 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;

【讨论】:

  • 这个答案太正面了。我有多愚蠢?非常感谢!
  • 我将使用标签来检查最大宽度,以便在需要时缩小列。
  • 嗯。我的回答最近被“不接受”。我想知道为什么。
  • stackoverflow.com/questions/13297508/… 我在使用您的代码时遇到了这个问题。如果到明天我找不到其他答案,我会检查你的。我真的需要这样做才能继续我的项目;(
  • 啊,好的。我在另一个帖子上发表了评论。这可能会有所帮助。
【解决方案2】:

已编辑:

我的第一个代码是关于将网格内的列与这个新代码相匹配,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;

我在 DataSet.AfterOpen 事件中调用它:

TGridHelper.AutoSizeColumns(MyDBGrid);

【讨论】:

  • 不幸的是,这个解决方案不适合我的需求。在此代码中,您拉伸列以使其不超过网格区域,但由于某些数据被剪切,因此内容受到损害。正确的是使文本内容而不是总列宽与总网格宽度相匹配。但感谢您的尝试。
  • 这不是问题的答案。
  • 否定是不公平的,因为 OP 没有首先解释他真正想要什么,现在我编辑了我的帖子以匹配来自同一单位的另一个代码的需求。
  • @NGLN,否决票不公平。我的答案基于 OP 的原始帖子,在他编辑并更好地解释了真正的需求之后,我更新了我的帖子。
  • +1;我在做了一个非常类似的实现后找到了很好的答案。细微的区别是,默认情况下,我使用 DbGrid 的 RowCount 来限制要检查的行(我这样做是因为已经从数据库中获取了这些记录),除非它是我扫描所有记录的 TClientDataSet(它们在内存中无论如何)。
【解决方案3】:

为什么要使用这么复杂的代码? :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;

【讨论】:

    【解决方案4】:

    对于要自动调整大小的每一列,设置属性SizePriority=1,对于固定列设置SizePriority=0,在您的情况下,只有最后一列会自动调整大小。

    然后设置属性grid.AutoFillColumns=true 就可以了。

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        此解决方案使所有列根据其内容扩展或收缩,而不关心是否必须有滚动条,并修复选定单元格绘制故障和记录指针故障。

        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;
        

        【讨论】:

          【解决方案7】:

          使用过程DbGrid1.AutoAdjustColumns就可以了。

          【讨论】:

          • 这是一个新程序还是在旧版本的 Delphi 中存在?
          • 最新版本的Delphi终于没有这个方法了
          • edn.embarcadero.com/article/27548 Embacadero 开发者社区发布了一个程序 - 见上文。
          【解决方案8】:

          你好使用这个程序。

          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;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-04-01
            • 2012-04-07
            • 2013-06-23
            • 1970-01-01
            • 1970-01-01
            • 2013-10-03
            • 2014-08-10
            • 2020-02-01
            相关资源
            最近更新 更多