Firemonkey 网格控制 - 将列右对齐

发布于 2025-01-04 19:23:46 字数 2199 浏览 1 评论 0原文

我正在使用 FireMonkey Grid 控件,但在尝试右对齐列时遇到持续的问题。从其他用户的帖子中,我设法创建了一个新的 TColumn 类型,对此应用了一种样式(文本为 HorzAlign=taTrailing),理论上 - 认为这将是解决方案。这些值由 OnGetValue 函数提供给网格控件。

然而问题是,虽然一开始看起来不错,但如果您滚动栏/鼠标滚轮等,新的 TColumn 类型列似乎无法使用下面的方法/代码正确刷新。这可能是网格的错误/功能(或者我这样做的方式)。我尝试过.ReAlign等...;但无济于事。让网格重新对齐的唯一方法是调整列大小,然后正确地重新绘制?

下面的代码显示它是一个简单的 TGrid,有 2 个列,1 个标准 StringColumn 和 1 个我的新 StringColNum(应用了右对齐)。 - 任何帮助表示感谢,因为这是任何网格工作的基本要求。

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Objects, FMX.Grid,
  FMX.Layouts, FMX.Edit;

type
  TForm1 = class(TForm)
    Grid1: TGrid;
    Button1: TButton;
    StyleBook1: TStyleBook;
    procedure Grid1GetValue(Sender: TObject; const Col, Row: Integer;
      var Value: Variant);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TStringColNum = class(TStringColumn)
  private
    function CreateCellControl: TStyledControl; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

constructor TStringColNum.Create(AOwner: TComponent);
begin
  inherited;
end;

function TStringColNum.CreateCellControl: TStyledControl;
var
  t:TEdit;
begin
  Result:=TStringColNum.Create(Self);
  Result.StyleLookup := 'textrightalign';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Grid1.AddObject(TStringColumn.Create(Self));
  Grid1.AddObject(TStringColNum.Create(Self)); // Right Aligned column?

  Grid1.RowCount:=5000;
  Grid1.ShowScrollBars:=True;
end;

procedure TForm1.Grid1GetValue(Sender: TObject; const Col, Row: Integer;
  var Value: Variant);
var
  cell: TStyledControl;
  t: TText;
begin
  if Col=0 then
    Value:='Row '+IntToStr(Row);;

  if Col=1 then
    begin
      cell := Grid1.Columns[Col].CellControlByRow(Row);
      if Assigned(cell) then
        begin
          t := (Cell.FindStyleResource('text') as TText);
          if Assigned(t) then
            t.Text:='Row '+IntToStr(Row);
        end;
    end;
end;

end.

亲切的问候。伊恩.

I am using the FireMonkey Grid control but have an on-going issue in trying to right align a column. From other users postings, I have managed to create a new TColumn type, apply a style to this (text as HorzAlign=taTrailing) and in theory - thought that this would be solution. The values are provided by the OnGetValue function to the Grid control.

The problem is however that although at first it looks OK, if you scroll the bar/mouse wheel etc. the new TColumn type column does not appear to refresh correctly using the method/code below. It could be a bug/feature of the Grid (or the way I am doing it). I have tried .ReAlign etc...; but to no avail. The only way to get the grid back in line is do a column resize for example - which then redraws correctly?

The code below shows that it is a simple TGrid, with 2 cols, 1 the standard StringColumn and 1 my new StringColNum (wuth right alignment applied). - Any help appreciated as this one is a basic requirement of any grid work.

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Objects, FMX.Grid,
  FMX.Layouts, FMX.Edit;

type
  TForm1 = class(TForm)
    Grid1: TGrid;
    Button1: TButton;
    StyleBook1: TStyleBook;
    procedure Grid1GetValue(Sender: TObject; const Col, Row: Integer;
      var Value: Variant);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TStringColNum = class(TStringColumn)
  private
    function CreateCellControl: TStyledControl; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

constructor TStringColNum.Create(AOwner: TComponent);
begin
  inherited;
end;

function TStringColNum.CreateCellControl: TStyledControl;
var
  t:TEdit;
begin
  Result:=TStringColNum.Create(Self);
  Result.StyleLookup := 'textrightalign';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Grid1.AddObject(TStringColumn.Create(Self));
  Grid1.AddObject(TStringColNum.Create(Self)); // Right Aligned column?

  Grid1.RowCount:=5000;
  Grid1.ShowScrollBars:=True;
end;

procedure TForm1.Grid1GetValue(Sender: TObject; const Col, Row: Integer;
  var Value: Variant);
var
  cell: TStyledControl;
  t: TText;
begin
  if Col=0 then
    Value:='Row '+IntToStr(Row);;

  if Col=1 then
    begin
      cell := Grid1.Columns[Col].CellControlByRow(Row);
      if Assigned(cell) then
        begin
          t := (Cell.FindStyleResource('text') as TText);
          if Assigned(t) then
            t.Text:='Row '+IntToStr(Row);
        end;
    end;
end;

end.

Kind regards. Ian.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

知你几分 2025-01-11 19:23:46

所有这些都提醒我,我还没有写关于此的博客文章。

无论如何,网格单元可以是 TStyledControl 的任何后代(基本上是任何控件)。文本单元格的默认值是 TTextCell,它只是一个 TEdit。作为 TEdit 意味着更改对齐方式非常简单:只需更改 TextAlign 属性即可。无需搞乱样式(除非您真的想要)。

您的列需要在 CreateCellControl 方法中创建单元格。您实际上正在创建列的实例,这是您的主要问题。

您的列不需要 Create 方法(它什么也不做),因此删除它(除非您需要它用于其他用途)并修改您的 CreateCellControl。

function TStringColNum.CreateCellControl: TStyledControl;
begin
  Result:=inherited;
  TTextCell(Result).TextAlign := taTrailing;
end;

最后,您的 GetValue 事件处理程序只需返回值即可:

procedure TForm1.Grid1GetValue(Sender: TObject; const Col, Row: Integer;
  var Value: Variant);
begin
  if Col=0 then
    Value:='Row '+IntToStr(Row);

  if Col=1 then
    Value := 'Row '+IntToStr(Row);
end;

All of which reminds me that I still haven't written my blog post about this.

Anyway, a grid cell can be any descendant of TStyledControl (basically any control). The default for a text cell is TTextCell, which is simply a TEdit. Being a TEdit means changing the alignment is really easy: just change the TextAlign property. No need to mess with styles (unless you really want to).

Your column needs to create your cells in the CreateCellControl method. You're actually creating an instance of your column which is your main problem.

You don't need the Create method for your column (it's doing nothing), so delete it (unless you need it for something else) and amend your CreateCellControl.

function TStringColNum.CreateCellControl: TStyledControl;
begin
  Result:=inherited;
  TTextCell(Result).TextAlign := taTrailing;
end;

Finally, your GetValue event handler needs do nothing more than return the value:

procedure TForm1.Grid1GetValue(Sender: TObject; const Col, Row: Integer;
  var Value: Variant);
begin
  if Col=0 then
    Value:='Row '+IntToStr(Row);

  if Col=1 then
    Value := 'Row '+IntToStr(Row);
end;
谁的新欢旧爱 2025-01-11 19:23:46

我认为这是内河码头的懒惰。

在 FMX.Grid.pas 中添加/修改 3 行解决了这个问题。

我建议不要修改原始的 FMX.Grid 路径,而是将原始的 FMX.Grid 路径复制到您的项目目录,包括在您的项目中(添加到项目)并添加/修改以下行。

TColumn = class(TStyledControl)
  private const
    HorzTextMargin = 2;
    VertTextMargin = 1;
  private
    FReadOnly: Boolean;
    FHorizontalAlign:TTextAlign;//Add this Line *********
    FEditMode: Integer;
    FApplyImmediately: boolean;
    ...
    ...
    procedure UpdateCell(ARow: Integer);
  published
    property HorizontalAlign: TTextAlign read FHorizontalAlign write FHorizontalAlign;//add this line *******
    property Align;
    property ClipChildren default False;

procedure TColumn.DefaultDrawCell(const Canvas: TCanvas; const Bounds: TRectF; const Row: Integer;
  const Value: TValue; const State: TGridDrawStates);
var
  R: TRectF;
  Layout: TTextLayout;
  LocalRow: Integer;
begin
  if FDrawable <> nil then
    FDrawable.DrawCell(Canvas, Bounds, Row, Value, State)
  else
...
...
      Layout.Opacity := AbsoluteOpacity;
      (*remark this line *****************
      Layout.HorizontalAlign := Grid.TextSettingsControl.ResultingTextSettings.HorzAlign;
      *)
      Layout.HorizontalAlign := HorizontalAlign;//add this line *****

最后您可以在项目中设置新属性。例如:

MyColumn.Horizo​​ntalAlign:=TTextAlign.taCenter;

I think it is a laziness of Embarcadero.

adding/modifying 3 lines in FMX.Grid.pas solves this problem.

instead of modifiying original FMX.Grid pas, I recommend copying original FMX.Grid pas to your Project directory, including in your Project (add to Project) and adding/modifiying following lines.

TColumn = class(TStyledControl)
  private const
    HorzTextMargin = 2;
    VertTextMargin = 1;
  private
    FReadOnly: Boolean;
    FHorizontalAlign:TTextAlign;//Add this Line *********
    FEditMode: Integer;
    FApplyImmediately: boolean;
    ...
    ...
    procedure UpdateCell(ARow: Integer);
  published
    property HorizontalAlign: TTextAlign read FHorizontalAlign write FHorizontalAlign;//add this line *******
    property Align;
    property ClipChildren default False;

procedure TColumn.DefaultDrawCell(const Canvas: TCanvas; const Bounds: TRectF; const Row: Integer;
  const Value: TValue; const State: TGridDrawStates);
var
  R: TRectF;
  Layout: TTextLayout;
  LocalRow: Integer;
begin
  if FDrawable <> nil then
    FDrawable.DrawCell(Canvas, Bounds, Row, Value, State)
  else
...
...
      Layout.Opacity := AbsoluteOpacity;
      (*remark this line *****************
      Layout.HorizontalAlign := Grid.TextSettingsControl.ResultingTextSettings.HorzAlign;
      *)
      Layout.HorizontalAlign := HorizontalAlign;//add this line *****

finally you can set the new property in your Project. e.g:

MyColumn.HorizontalAlign:=TTextAlign.taCenter;

樱花坊 2025-01-11 19:23:46

降序列不能很好地与实时绑定配合使用,因为绑定管理器会创建列,因此您必须搞乱降序列。在我看来既不优雅也不实用。

只需在网格 OnPainting 事件中对齐单元格即可。

I := Col;
for J := 0 to Grid1.RowCount - 1 do
begin
  T := TTextCell(Grid1.Columns[I].Children[J]);
  T.TextAlign := TTextAlign.taTrailing;
end;

Descending columns does not work well with livebindings as the bindmanager creates the columns so you have to mess with descending that. Neither elegant nor practical in my view.

Simply align your cells in the grid OnPainting event.

I := Col;
for J := 0 to Grid1.RowCount - 1 do
begin
  T := TTextCell(Grid1.Columns[I].Children[J]);
  T.TextAlign := TTextAlign.taTrailing;
end;
朮生 2025-01-11 19:23:46

如果您在自定义正在创建的列类的机会较少时使用实时绑定,但您可以为 Column 创建帮助程序,以设置各个单元格控件的某些属性。不太优雅,但简单有效:

unit GridColumnHelper;

interface

uses
  Fmx.Types, Fmx.Controls, Fmx.Grid, Fmx.Edit;

type
  TGridColumnHelper = class helper for TColumn
  public
    procedure SetEditMaxLength(aValue: Integer);
    procedure SetEditTextAlign(aValue: TTextAlign);
  end;

implementation

{ TGridColumnHelper }

procedure TGridColumnHelper.SetEditMaxLength(aValue: Integer);
var
  lControl: TStyledControl;
begin
  for lControl in FCellControls do
  begin
    if lControl is TEdit then
      (lControl as TEdit).MaxLength := aValue;
  end;
end;

procedure TGridColumnHelper.SetEditTextAlign(aValue: TTextAlign);
var
  lControl: TStyledControl;
begin
  for lControl in FCellControls do
  begin
    if lControl is TEdit then
      (lControl as TEdit).TextAlign := aValue;
  end;
end;

end.

绑定填充网格后,您可以调用助手:

MyGrid.Columns[0].SetEditTextAlign(TTextAlign.taTrailing);
MyGrid.Columns[1].SetEditMaxLength(15);

If you use livebindings when you have less chance to customize the column class which is being created, but you can create helpers for Column which sets some attributes of individual cell controls. Not too elegant but simple and works:

unit GridColumnHelper;

interface

uses
  Fmx.Types, Fmx.Controls, Fmx.Grid, Fmx.Edit;

type
  TGridColumnHelper = class helper for TColumn
  public
    procedure SetEditMaxLength(aValue: Integer);
    procedure SetEditTextAlign(aValue: TTextAlign);
  end;

implementation

{ TGridColumnHelper }

procedure TGridColumnHelper.SetEditMaxLength(aValue: Integer);
var
  lControl: TStyledControl;
begin
  for lControl in FCellControls do
  begin
    if lControl is TEdit then
      (lControl as TEdit).MaxLength := aValue;
  end;
end;

procedure TGridColumnHelper.SetEditTextAlign(aValue: TTextAlign);
var
  lControl: TStyledControl;
begin
  for lControl in FCellControls do
  begin
    if lControl is TEdit then
      (lControl as TEdit).TextAlign := aValue;
  end;
end;

end.

After the binding has filled the grid, you can call the helpers:

MyGrid.Columns[0].SetEditTextAlign(TTextAlign.taTrailing);
MyGrid.Columns[1].SetEditMaxLength(15);
执手闯天涯 2025-01-11 19:23:46

“suat dmk”的解决方案工作正常,如果您要使用数据库链接,则必须重新编译 Fmx.Bind.DBLinks.pas 和 Fmx.Bind.Editors.pas 。

之后,您只需放入 OnPainting 事件:

SGrid1.ColumnByIndex(1).HorizontalAlign := TTextAlign.Leading;

Solution of "suat dmk" is working fine you have to recompile Fmx.Bind.DBLinks.pas and Fmx.Bind.Editors.pas if you are gonna use DB links.

After that, you simply put in OnPainting event:

SGrid1.ColumnByIndex(1).HorizontalAlign := TTextAlign.Leading;
ぽ尐不点ル 2025-01-11 19:23:46

另一个解决方案:

Grid1.ApplyStyleLookup();
MyCol1.DefaultTextSettings.HorzAlign:=TTextAlign.taCenter;

another solution:

Grid1.ApplyStyleLookup();
MyCol1.DefaultTextSettings.HorzAlign:=TTextAlign.taCenter;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文