XE7下修改FMX.Grid.pas解决Grid列头与文本内容的样式设定,实现标题栏文字居中,内容的文本可右对齐。

  在XE6上,已经有人研究过 Grid 的样式。在QQ群里,【深圳从头再来】说它的XE5,对于设置列头列内容的样式很完美,并帮我做了一个测试例子,可是发给我在XE6上编译,却没有想要的结果。尽管对于列头的样式,在点过按钮中确实生效,但是我想在Create事件中调用按钮的样式设定,却不成功,不知是什么原因。后来,我把XE6卸载,安装了XE7,运行后,与XE6上的不理想效果一致,这令我很惊讶。按道理,工具版本的升级,只可能更方便更完美,却是如此的不尽人意。网上也参考了【红鱼儿糊思乱想】的Grid试用结果,并且,后来【广州weii】也进行了试验,博文如下:http://www.cnblogs.com/weii/p/3977320.html。weii是最接近效果的,它设置标头的办法与红鱼儿博文中差不多。另外,对StringGrid进行了TextSettings设置,这个参数影响到网格内所有列的显示样式。仍然是不能独立为各个列设置对齐方式。

  我们的习惯,标题的文字一定是居中的,并且有时为了突出显示,或是设为粗体,或是红色什么的。对于内容,比如显示的字符长度固定,往往居中;对于金额,右对齐。可是,目前来说这个Grid,已有的属性无法做到。而且,在设置统一右对齐时,太靠右了,列头右线和内容右线也有1个像素的偏差。如下图所展现的:

 

  要找到解决办法,我先尝试着看一看TStringGrid类的代码,它在C:\Program Files (x86)\Embarcadero\Studio\15.0\source\fmx\FMX.Grid.pas文件中。因此,我们可以把这个源文件复制一份,放在当前测试的工程目录下。然后对代码进行更改,因为编译时,对于同名单元,优先当前目录的源文件。TStringGrid是TCustomGrid的子类,同样,TGrid也是从TCustomGrid继承而来的。TCustomGrid中各列,其基类是TColumn,所以不管是TStringColumn, TDateColumn,TCheckColumn,都有一些共同属性。通过对FMX.Grid.pas的研究修改,最终实现了想要的效果。现把要FMX.Grid.pas中增加的代码发布出来:

 1. TColumn类定义进行修改,第4行代码是原来的设置值为2,注释掉,设为5,使得显示的内容离左、右边线稍远一点点。

 1   TColumn = class(TStyledControl)
 2   private const
 3 { 边距设大一点,效果更美观些 }
 4 //  HorzTextMargin = 2;
 5     HorzTextMargin = 5;
 6 {\\\ end add 2014/9/18}
 7     VertTextMargin = 1;
 8   private
 9     ......
10     [Weak] FGrid: TCustomGrid;
11 {/// 为列头和内容设置样式的参数 }
12     FHeadAlign : TTextAlign;      // 列头文字对齐方式
13     FHeadFontColor : TAlphaColor; // 列头文字颜色
14     FHeadFontName  : TFontName;   // 列头文字字体
15     FHeadFontSize  : Single;      // 列头文字大小
16     FHeadFontStyle : TFontStyles; // 列头文字样式
17     FTextAlign : TTextAlign;      // 内容文本对应方式
18     FTextFontColor : TAlphaColor; // 内容文本颜色
19     FTextFontName  : TFontName;   // 内容文本字体
20     FTextFontSize  : Single;      // 内容文本大小
21     FTextFontStyle : TFontStyles; // 内容文本样式
22 {\\\ end add 2014/9/18}
23     procedure SetHeader(const Value: string);
24     ......
25   published
26 {/// 放出参数可进行设置 }
27     property HeadAlign : TTextAlign read FHeadAlign write FHeadAlign;
28     property HeadFontColor : TAlphaColor read FHeadFontColor write FHeadFontColor;
29     property HeadFontName  : TFontName read FHeadFontName write FHeadFontName;
30     property HeadFontSize  : Single read FHeadFontSize write FHeadFontSize;
31     property HeadFontStyle : TFontStyles read FHeadFontStyle write FHeadFontStyle;
32     property TextAlign : TTextAlign read FTextAlign write FTextAlign;
33     property TextFontColor : TAlphaColor read FTextFontColor write FTextFontColor;
34     property TextFontName  : TFontName read FTextFontName write FTextFontName;
35     property TextFontSize  : Single read FTextFontSize write FTextFontSize;
36     property TextFontStyle : TFontStyles read FTextFontStyle write FTextFontStyle;
37 {\\\ end add 2014/9/18}
38     ......
39 end;

 

2. TColumn的Create方法,设置加入属性的默认值,此处设置列头(标题栏)默认居中。

 1 constructor TColumn.Create(AOwner: TComponent);
 2 begin
 3   inherited;
 4 {/// 增加参数设置默认值 }
 5   FHeadAlign := TTextAlign(0); // 列头默认居中
 6   FHeadFontColor := TAlphaColors.Black;
 7   FHeadFontName := 'Tahoma';
 8   FHeadFontSize := 12.0;
 9   FHeadFontStyle := [];
10   FTextAlign := TTextAlign(1);
11   FTextFontColor := TAlphaColors.Black;
12   FTextFontName := 'Tahoma';
13   FTextFontSize := 12.0;
14   FTextFontStyle := [];
15 {\\\ end add 2014/9/18}
16   FLastRow := -1;
17   FDrawLayouts := TObjectList<TTextLayout>.Create;
18   Width := 100;
19   HitTest := False;
20   CanFocus := False;
21   FEditMode := -1;
22   FApplyImmediately := True;
23 end;

 

3. 列内容的绘制效果定义,全在DefaultDrawCell中了。

 1 procedure TColumn.DefaultDrawCell(const Canvas: TCanvas; const Bounds: TRectF; const Row: Integer;
 2   const Value: TValue; const State: TGridDrawStates);
 3 var
 4   R: TRectF;
 5   Layout: TTextLayout;
 6   LocalRow: Integer;
 7 begin
 8   if FDrawable <> nil then
 9     FDrawable.DrawCell(Canvas, Bounds, Row, Value, State)
10   else
11   begin
12     R := Bounds;
13 { 根据对齐设置,进行调整 }
14 //    R.Inflate(-HorzTextMargin, -VertTextMargin); // 原来是这句,注释了,由下面部分来设定。解决右对齐时太靠边线的问题
15     if FTextAlign = TTextAlign.Leading then
16       R.Inflate(-HorzTextMargin, -VertTextMargin)
17     else if FTextAlign = TTextAlign.Trailing then
18       R.Inflate(HorzTextMargin, -VertTextMargin);
19 {\\\ end add 2014/9/18}
20     LocalRow := Row - Grid.TopRow;
21     if LocalRow >= FDrawLayouts.Count then
22     begin
23       Layout := TTextLayoutManager.DefaultTextLayout.Create(Canvas);
24       FDrawLayouts.Add(Layout);
25     end
26     else
27       Layout := FDrawLayouts[LocalRow];
28 
29     Layout.BeginUpdate;
30     try
31       Layout.TopLeft := R.TopLeft;
32       Layout.Text := ValueToString(Value);
33       Layout.MaxSize := PointF(Width, Grid.RowHeight);
34       Layout.WordWrap := False;
35       Layout.Opacity := AbsoluteOpacity;
36       Layout.HorizontalAlign := Grid.TextSettingsControl.ResultingTextSettings.HorzAlign;
37       Layout.VerticalAlign := Grid.TextSettingsControl.ResultingTextSettings.VertAlign;
38       Layout.Font.Assign(Grid.TextSettingsControl.ResultingTextSettings.Font);
39       Layout.Color := Grid.TextSettingsControl.ResultingTextSettings.FontColor;
40       Layout.Trimming := TTextTrimming.Character;
41 { 设置文本内容显示的样式 }
42       Layout.Font.Family := FTextFontName;
43       Layout.Font.Size := FTextFontSize;
44       Layout.Font.Style := FTextFontStyle;
45       Layout.Color := FTextFontColor;
46       Layout.HorizontalAlign := FTextAlign;
47       Layout.VerticalAlign := TTextAlign(0); // 如有特别要求,可注释此行
48 {\\\ end add 2014/9/18}
49     finally
50       Layout.EndUpdate;
51     end;
52     Layout.RenderLayout(Canvas);
53   end;
54 end;

从上面代码第36~39行可知,原来在Grid中设置的TextSettings值,在所有列都应用它的设定值了。因此,添加第42~47行代码替换。

 

4. 列头样式的设定,需要更改TCustomGrid.UpdateHeader部分:

 1 procedure TCustomGrid.UpdateHeader;
 2 var
 3   I: Integer;
 4   Item: THeaderItem;
 5   C: TFmxObject;
 6   LHeader: TOpenHeader;
 7 begin
 8   if not Assigned(FHeader) then
 9     Exit;
10   LHeader := TOpenHeader(FHeader);
11 
12   LHeader.Sizing := TGridOption.ColumnResize in Options;
13   LHeader.DragReorder := TGridOption.ColumnMove in Options;
14 { 加1个值,让列头与内容右线对齐 }
15   LHeader.Offset := -ViewportPosition.X + 1;
16 {\\\ end add 2014/9/18}
17   LHeader.RemoveObject(LHeader.LastItem);
18   ......
19   for I := 0 to ColumnCount - 1 do
20   begin
21     TGridHeaderItem(LHeader.Children[I]).Text := Columns[I].Header;
22     TGridHeaderItem(LHeader.Children[I]).Width := Columns[I].Width;
23     TGridHeaderItem(LHeader.Children[I]).Visible := Columns[I].Visible;
24     TGridHeaderItem(LHeader.Children[I]).Column := Columns[I];
25 { 设置列头的样式 }
26     with TGridHeaderItem(LHeader.Children[I]) do begin
27       StyledSettings := []; // 如果没有这句,则字体大小,颜色不会改变
28       TextAlign := Columns[I].HeadAlign;
29       Font.Family := Columns[I].HeadFontName;
30       Font.Size := Columns[I].HeadFontSize;
31       Font.Style := Columns[I].HeadFontStyle;
32       FontColor := Columns[I].HeadFontColor;
33     end;
34 {\\\ end add 2014/9/18}
35   end;
36   LHeader.Realign;
37 
38   if FHeader.Visible <> (TGridOption.Header in FOptions) then
39   begin
40     FHeader.Visible := TGridOption.Header in FOptions;
41     RealignContent;
42   end;
43 end;

 

至此,源码部分已经更改完毕。我们测试例子,放上Button1加载数据,Button2对齐数据,添加代码如下:

 1 procedure TForm1.FormCreate(Sender: TObject);
 2 begin
 3   Button1Click(nil);
 4 end;
 5 
 6 procedure TForm1.Button1Click(Sender: TObject);
 7 var i,j:Integer;
 8 begin
 9   StringGrid1.RowCount := 10;
10   StringGrid1.BeginUpdate;
11   for j := 0 to 2 do
12   begin
13     StringGrid1.Columns[j].Width := 80;
14     for I := 0 to 9 do
15       StringGrid1.Cells[j, I] :=  'XE7-'+inttostr(i)+inttostr(j);
16   end;
17   StringGrid1.EndUpdate;
18 end;
19 
20 procedure TForm1.Button2Click(Sender: TObject);
21 var i: Integer;
22 begin
23   StringGrid1.BeginUpdate;
24   for i := 0 to StringGrid1.ColumnCount - 1 do
25   begin // 设置所有列头文字,蓝色粗体并大一些,
26     StringGrid1.Columns[i].HeadFontColor := TAlphaColors.Blue;
27     StringGrid1.Columns[i].HeadFontSize := 15;
28     StringGrid1.Columns[i].HeadFontStyle := [TFontStyle.fsBold];
29     //StringGrid1.Columns[i].HeadAlign := TTextAlign(2); // 默认是居中了,也可以更改
30   end;
31   // 设置第二列文本,居中,绿字
32   StringColumn2.TextAlign := TTextAlign(0);
33   StringColumn2.TextFontName := '宋体';
34   StringColumn2.TextFontColor := TAlphaColors.Green;
35   // 设置第三列文本,右对齐,红字
36   StringColumn3.TextAlign := TTextAlign(2);
37   StringColumn3.TextFontColor := TAlphaColors.Red;
38 
39   StringGrid1.RealignContent; // 使内容文本样式有效
40   StringGrid1.EndUpdate;      // 使列头文字样式有效
41 end;

 

运行效果如下:

 

 

后记:所增加的10个参数,最理想的是在可视化设计时设置。可惜我不知道FMX.Grid.pas是在系统的哪个dpk包,所以没法重编译安装一下。
并且,之所以用10个参数,而不能像TStringGrid的TextSetting参数,是因为之前我也用了两个
    FHeadSettings : TTextSettings
    FTextSettings : TTextSettings
来包含现在的,但是这是一个组合的属性类,在TColumn的Create时也创建FHeadSettings,FTextSettings,并且在Destory释放。
但是在测试例子赋值后,DefaultDrawCell,UpdateHeader执行时却仍得不到期望的,所以只得精简出10个有用的来设置。

使用方法:将更改过的 FMX.Grid.pas 拷到你的Project目录下,并最好加到 Project 中。至于其它版本,应该根据这个思路修改,再去测试调整。


本测试例子,感谢【[深圳]从头再来(358880222)】给我的帮助,以及网络资源一大堆我记不住名字的有名氏。
有改进的东东,比如多行标题,某标题列还能合并,加入合计栏等...  不妨email给我一份:3822640@qq.com,共同学习。

 

posted @ 2014-09-20 16:18  坚韧如松  阅读(1689)  评论(0)    收藏  举报