Delphi:如何使TStringGrid中单元格的文本居中对齐?

16

这似乎是一个很显然的需求。我想让文本位于单元格的中央,但出于某些原因,我在属性中找不到它。我应该如何做到这一点?

2个回答

21

在TStringGrid中没有居中文本的属性,但是你可以在DrawCell事件中进行操作,如下所示:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  S: string;
  SavedAlign: word;
begin
  if ACol = 1 then begin  // ACol is zero based
    S := StringGrid1.Cells[ACol, ARow]; // cell contents
    SavedAlign := SetTextAlign(StringGrid1.Canvas.Handle, TA_CENTER);
    StringGrid1.Canvas.TextRect(Rect,
      Rect.Left + (Rect.Right - Rect.Left) div 2, Rect.Top + 2, S);
    SetTextAlign(StringGrid1.Canvas.Handle, SavedAlign);
  end;
end;

我从这里发布的代码。

更新:

要在单元格中编写文本时居中,将此代码添加到GetEditText事件中:

procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
  var Value: string);
var
  S : String;
  I: Integer;
  IE : TInplaceEdit ;
begin
  for I := 0 to StringGrid1.ControlCount - 1 do
    if StringGrid1.Controls[i].ClassName = 'TInplaceEdit' then
    begin
      IE := TInplaceEdit(StringGrid1.Controls[i]);
      ie.Alignment := taCenter
    end;
end;

谢谢。所以,如果我希望它在用户输入单元格时居中,那么我应该在onEdit()中这样做吗? - Mahm00d
上面的代码是在OnDrawCell事件中实现的,应该保留在那里。如果您希望输入在用户居中时居中显示,则应使用编辑器TEdit/TWhateverEdit的绘制事件来实现。 - zz1433
谢谢你的建议,Mohammed。这是一种不错的实现方式。我在想,是否有更好的组件用于在表格中添加/编辑数据,例如StringGrid?因为StringGrid在功能上有些受限。 - Mahm00d
你可以从www.bergsoft.net查看NextGrid或者从TMSSoftware查看TAdvStringGrid,前者轻便快速,并且有Delphi 6和7的免费版本,后者更加强大。 - Mohammed Nasman

5
这个方案比其他方案好得多,而且它们中有一些过程存在错别字 TStringGrid.SetCellsAlignmentTStringGrid.SetCellsAlignment(-1 < Index) 比较是正确的,但是 thenelse 部分被交换了... 正确版本(即此版本)将显示当索引大于-1时,它将覆盖存储的值,否则它将添加一个新条目,其他版本将执行相反的操作,从而带来一个列表索引消息错误,请注意检查。
我还使其能够全部在另一个单独的单元中,因此在此处(希望现在它是正确的,并感谢您检测到这样的错别字)。
unit AlignedTStringGrid;

interface

uses Windows,SysUtils,Classes,Grids;

type 
  TStringGrid=class(Grids.TStringGrid)
  private
    FCellsAlignment:TStringList;
    FColsDefaultAlignment:TStringList;
    function GetCellsAlignment(ACol,ARow:Integer):TAlignment;
    procedure SetCellsAlignment(ACol,ARow:Integer;const Alignment:TAlignment);
    function GetColsDefaultAlignment(ACol:Integer):TAlignment;
    procedure SetColsDefaultAlignment(ACol:Integer;const Alignment:TAlignment);
  protected
    procedure DrawCell(ACol,ARow:Longint;ARect:TRect;AState:TGridDrawState);override;
  public
    constructor Create(AOwner:TComponent);override;
    destructor Destroy;override;
    property CellsAlignment[ACol,ARow:Integer]:TAlignment read GetCellsAlignment write SetCellsAlignment;
    property ColsDefaultAlignment[ACol:Integer]:TAlignment read GetColsDefaultAlignment write SetColsDefaultAlignment;
  end;

implementation

constructor TStringGrid.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FCellsAlignment:=TStringList.Create;
  FCellsAlignment.CaseSensitive:=True;
  FCellsAlignment.Sorted:=True;
  FCellsAlignment.Duplicates:=dupIgnore;
  FColsDefaultAlignment:=TStringList.Create;
  FColsDefaultAlignment.CaseSensitive:=True;
  FColsDefaultAlignment.Sorted:=True;
  FColsDefaultAlignment.Duplicates:=dupIgnore;
end;

destructor TStringGrid.Destroy;
begin
  FCellsAlignment.Free;
  FColsDefaultAlignment.Free;
  inherited Destroy;
end;

procedure TStringGrid.SetCellsAlignment(ACol,ARow: Integer; const Alignment: TAlignment);
var
  Index:Integer;
begin
  if (-1 < Index) then begin
    FCellsAlignment.Objects[Index]:= TObject(Alignment);
  end else begin
    FCellsAlignment.AddObject(IntToStr(ACol) + '-' + IntToStr(ARow), TObject(Alignment));
  end;
end;

function TStringGrid.GetCellsAlignment(ACol,ARow: Integer): TAlignment;
var
  Index:Integer;
begin
  Index:= FCellsAlignment.IndexOf(IntToStr(ACol)+'-'+IntToStr(ARow));
  if (-1 < Index) then begin
    GetCellsAlignment:= TAlignment(FCellsAlignment.Objects[Index]);
  end else begin
    GetCellsAlignment:= ColsDefaultAlignment[ACol];
  end;
end;

procedure TStringGrid.SetColsDefaultAlignment(ACol: Integer; const Alignment: TAlignment);
var
  Index:Integer;
begin
  Index:= FColsDefaultAlignment.IndexOf(IntToStr(ACol));
  if (-1 < Index) then begin
    FColsDefaultAlignment.Objects[Index]:= TObject(Alignment);
  end else begin
    FColsDefaultAlignment.AddObject(IntToStr(ACol), TObject(Alignment));
  end;
end;

function TStringGrid.GetColsDefaultAlignment(ACol:Integer):TAlignment;
var
  Index:Integer;
begin
  Index:= FColsDefaultAlignment.IndexOf(IntToStr(ACol));
  if (-1 < Index) then begin
    GetColsDefaultAlignment:= TAlignment(FColsDefaultAlignment.Objects[Index]);
  end else begin
    GetColsDefaultAlignment:=taLeftJustify;
  end;
end;

procedure TStringGrid.DrawCell(ACol,ARow:Longint;ARect:TRect;AState:TGridDrawState);
var
  Old_DefaultDrawing:Boolean;
begin
  if DefaultDrawing then begin
    case CellsAlignment[ACol,ARow] of
      taLeftJustify: begin
        Canvas.TextRect(ARect,ARect.Left+2,ARect.Top+2,Cells[ACol,ARow]);
      end;
      taRightJustify: begin
        Canvas.TextRect(ARect,ARect.Right -2 -Canvas.TextWidth(Cells[ACol,ARow]), ARect.Top+2,Cells[ACol,ARow]);
      end;
      taCenter: begin
        Canvas.TextRect(ARect,(ARect.Left+ARect.Right-Canvas.TextWidth(Cells[ACol,ARow]))div 2,ARect.Top+2,Cells[ACol,ARow]);
      end;
    end;
  end;
  Old_DefaultDrawing:= DefaultDrawing;
  DefaultDrawing:=False;
  inherited DrawCell(ACol,ARow,ARect,AState);
  DefaultDrawing:= Old_DefaultDrawing;
end;

end.

这是一个完整的单元,将其保存到名为 AlignedTStringGrid.pas 的文件中。
然后在任何你拥有 TStringGrid 的窗体上,在接口使用子句的末尾添加 ,AlignedTStringGrid
注意:行也可以这样做,但目前我不知道如何混合两者(列和行),因为要选择优先级,如果有人对此非常感兴趣,请告诉我。
P.D.:对于 TEdit,相同的想法也是可行的,只需在 stackoverflow.com 上搜索 TEdit.CreateParams 或阅读文章 如何设置 TEdit 控件的文本对齐方式

@kleopatra,我已经安排删除错误的解决方案,这是正确的解决方案。 - Johan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接