您的位置:首页 > Web前端 > CSS

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

2014-09-20 16:18 573 查看
  在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,使得显示的内容离左、右边线稍远一点点。

TColumn = class(TStyledControl)
private const
{ 边距设大一点,效果更美观些 }
//  HorzTextMargin = 2;
HorzTextMargin = 5;
{\\\ end add 2014/9/18}
VertTextMargin = 1;
private
......
[Weak] FGrid: TCustomGrid;
{/// 为列头和内容设置样式的参数 }
FHeadAlign : TTextAlign;      // 列头文字对齐方式
FHeadFontColor : TAlphaColor; // 列头文字颜色
FHeadFontName  : TFontName;   // 列头文字字体
FHeadFontSize  : Single;      // 列头文字大小
FHeadFontStyle : TFontStyles; // 列头文字样式
FTextAlign : TTextAlign;      // 内容文本对应方式
FTextFontColor : TAlphaColor; // 内容文本颜色
FTextFontName  : TFontName;   // 内容文本字体
FTextFontSize  : Single;      // 内容文本大小
FTextFontStyle : TFontStyles; // 内容文本样式
{\\\ end add 2014/9/18}
procedure SetHeader(const Value: string);
......
published
{/// 放出参数可进行设置 }
property HeadAlign : TTextAlign read FHeadAlign write FHeadAlign;
property HeadFontColor : TAlphaColor read FHeadFontColor write FHeadFontColor;
property HeadFontName  : TFontName read FHeadFontName write FHeadFontName;
property HeadFontSize  : Single read FHeadFontSize write FHeadFontSize;
property HeadFontStyle : TFontStyles read FHeadFontStyle write FHeadFontStyle;
property TextAlign : TTextAlign read FTextAlign write FTextAlign;
property TextFontColor : TAlphaColor read FTextFontColor write FTextFontColor;
property TextFontName  : TFontName read FTextFontName write FTextFontName;
property TextFontSize  : Single read FTextFontSize write FTextFontSize;
property TextFontStyle : TFontStyles read FTextFontStyle write FTextFontStyle;
{\\\ end add 2014/9/18}
......
end;


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

constructor TColumn.Create(AOwner: TComponent);
begin
inherited;
{/// 增加参数设置默认值 }
FHeadAlign := TTextAlign(0); // 列头默认居中
FHeadFontColor := TAlphaColors.Black;
FHeadFontName := 'Tahoma';
FHeadFontSize := 12.0;
FHeadFontStyle := [];
FTextAlign := TTextAlign(1);
FTextFontColor := TAlphaColors.Black;
FTextFontName := 'Tahoma';
FTextFontSize := 12.0;
FTextFontStyle := [];
{\\\ end add 2014/9/18}
FLastRow := -1;
FDrawLayouts := TObjectList<TTextLayout>.Create;
Width := 100;
HitTest := False;
CanFocus := False;
FEditMode := -1;
FApplyImmediately := True;
end;


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

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
begin
R := Bounds;
{ 根据对齐设置,进行调整 }
//    R.Inflate(-HorzTextMargin, -VertTextMargin); // 原来是这句,注释了,由下面部分来设定。解决右对齐时太靠边线的问题
if FTextAlign = TTextAlign.Leading then
R.Inflate(-HorzTextMargin, -VertTextMargin)
else if FTextAlign = TTextAlign.Trailing then
R.Inflate(HorzTextMargin, -VertTextMargin);
{\\\ end add 2014/9/18}
LocalRow := Row - Grid.TopRow;
if LocalRow >= FDrawLayouts.Count then
begin
Layout := TTextLayoutManager.DefaultTextLayout.Create(Canvas);
FDrawLayouts.Add(Layout);
end
else
Layout := FDrawLayouts[LocalRow];

Layout.BeginUpdate;
try
Layout.TopLeft := R.TopLeft;
Layout.Text := ValueToString(Value);
Layout.MaxSize := PointF(Width, Grid.RowHeight);
Layout.WordWrap := False;
Layout.Opacity := AbsoluteOpacity;
Layout.HorizontalAlign := Grid.TextSettingsControl.ResultingTextSettings.HorzAlign;
Layout.VerticalAlign := Grid.TextSettingsControl.ResultingTextSettings.VertAlign;
Layout.Font.Assign(Grid.TextSettingsControl.ResultingTextSettings.Font);
Layout.Color := Grid.TextSettingsControl.ResultingTextSettings.FontColor;
Layout.Trimming := TTextTrimming.Character;
{ 设置文本内容显示的样式 }
Layout.Font.Family := FTextFontName;
Layout.Font.Size := FTextFontSize;
Layout.Font.Style := FTextFontStyle;
Layout.Color := FTextFontColor;
Layout.HorizontalAlign := FTextAlign;
Layout.VerticalAlign := TTextAlign(0); // 如有特别要求,可注释此行
{\\\ end add 2014/9/18}
finally
Layout.EndUpdate;
end;
Layout.RenderLayout(Canvas);
end;
end;


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

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

procedure TCustomGrid.UpdateHeader;
var
I: Integer;
Item: THeaderItem;
C: TFmxObject;
LHeader: TOpenHeader;
begin
if not Assigned(FHeader) then
Exit;
LHeader := TOpenHeader(FHeader);

LHeader.Sizing := TGridOption.ColumnResize in Options;
LHeader.DragReorder := TGridOption.ColumnMove in Options;
{ 加1个值,让列头与内容右线对齐 }
LHeader.Offset := -ViewportPosition.X + 1;
{\\\ end add 2014/9/18}
LHeader.RemoveObject(LHeader.LastItem);
......
for I := 0 to ColumnCount - 1 do
begin
TGridHeaderItem(LHeader.Children[I]).Text := Columns[I].Header;
TGridHeaderItem(LHeader.Children[I]).Width := Columns[I].Width;
TGridHeaderItem(LHeader.Children[I]).Visible := Columns[I].Visible;
TGridHeaderItem(LHeader.Children[I]).Column := Columns[I];
{ 设置列头的样式 }
with TGridHeaderItem(LHeader.Children[I]) do begin
StyledSettings := []; // 如果没有这句,则字体大小,颜色不会改变
TextAlign := Columns[I].HeadAlign;
Font.Family := Columns[I].HeadFontName;
Font.Size := Columns[I].HeadFontSize;
Font.Style := Columns[I].HeadFontStyle;
FontColor := Columns[I].HeadFontColor;
end;
{\\\ end add 2014/9/18}
end;
LHeader.Realign;

if FHeader.Visible <> (TGridOption.Header in FOptions) then
begin
FHeader.Visible := TGridOption.Header in FOptions;
RealignContent;
end;
end;


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

procedure TForm1.FormCreate(Sender: TObject);
begin
Button1Click(nil);
end;

procedure TForm1.Button1Click(Sender: TObject);
var i,j:Integer;
begin
StringGrid1.RowCount := 10;
StringGrid1.BeginUpdate;
for j := 0 to 2 do
begin
StringGrid1.Columns[j].Width := 80;
for I := 0 to 9 do
StringGrid1.Cells[j, I] :=  'XE7-'+inttostr(i)+inttostr(j);
end;
StringGrid1.EndUpdate;
end;

procedure TForm1.Button2Click(Sender: TObject);
var i: Integer;
begin
StringGrid1.BeginUpdate;
for i := 0 to StringGrid1.ColumnCount - 1 do
begin // 设置所有列头文字,蓝色粗体并大一些,
StringGrid1.Columns[i].HeadFontColor := TAlphaColors.Blue;
StringGrid1.Columns[i].HeadFontSize := 15;
StringGrid1.Columns[i].HeadFontStyle := [TFontStyle.fsBold];
//StringGrid1.Columns[i].HeadAlign := TTextAlign(2); // 默认是居中了,也可以更改
end;
// 设置第二列文本,居中,绿字
StringColumn2.TextAlign := TTextAlign(0);
StringColumn2.TextFontName := '宋体';
StringColumn2.TextFontColor := TAlphaColors.Green;
// 设置第三列文本,右对齐,红字
StringColumn3.TextAlign := TTextAlign(2);
StringColumn3.TextFontColor := TAlphaColors.Red;

StringGrid1.RealignContent; // 使内容文本样式有效
StringGrid1.EndUpdate;      // 使列头文字样式有效
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,共同学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐