視圖用來表現數據,也是用戶接口。當數據更新時,視圖應該隨之改變,在交互過程中,視圖需要響應用戶,這些情況下都會引起視圖的繪制。 cxGrid可以用多種視圖表現關系型數據,最常用的是表格視圖,我們以表格視圖作為默認的對象,分析cxGrid用以實現視圖繪制的基本結構。
表格視圖按行,列布局,行優先順序繪制,繪制的基本元素是行和單元(cell)。由于數據內容的動態性,行是動態生成的。表格視圖提供了各種可定制性,包括可選的分組行風格和若干自定義風格,這些復雜特性背后有很好的設計。
視圖繪制相關的幾組類:
ViewInfo類族:
描述視圖元素的繪制信息,視圖元素要繪制成什么樣子,完全由其ViewInfo確定。祖先類是TcxCustomGridCellViewInfo,數據行,數據單元,分組行等視圖元素以及視圖本身都有相應的派生類。
Painter類族:
按照ViewInfo,在畫布上繪制視圖元素。祖先類是TcxCustomGridCellPainter。 TcxCustomGridCellPainter = class
private
FCanvas: TcxCanvas;
FViewInfo: TcxCustomGridCellViewInfo;
View類族:
整個視圖的描述,包括了各種設置信息。祖先是TcxCustomGridView。
View和ViewInfo的不同在ViewInfo描述繪制信息,而View描述設置信息,ViewInfo是動態構造的,當Grid創建時,如果有一個分組多條記錄,那么每條記錄會生成一個ViewInfo實例,如果收起分組,這些實例將被銷毀,展開分組,會再次生成每條記錄的ViewInfo實例,而一個表格視圖始終只有一個實例。
LookAndFeelPainter類族:
用于進行有關分組行風格的繪制。祖先是TcxCustomLookAndFeelPainter。
繪制視圖元素時,涉及到分組行風格(GroupRowStyle)的繪制任務,都被委托給LookAndFeelPainter類的實例,由此實現多態的風格。
Style和Styles類族:
Style類的祖先是TcxCustomStyle,Styles類的祖先是TcxCustomStyles。TcxCustomStyle類表示一種自定義風格,TcxCustomStyles類表示一組風格。TcxCustomStyles內部用一個map保存這些風格,給出鍵,可通過Values屬性取出指定的風格。
TcxCustomStyles = class(TcxInterfacedPersistent, IcxStyleChangeListener)
public
property Values[Index: Integer]: TcxCustomStyle read GetValue write SetValue;
鍵的取值范圍如下:
vsCustomTableFirst = vsCustomLast + 1;
vsContent = vsCustomTableFirst;
vsContentEven = vsCustomTableFirst + 1;
vsContentOdd = vsCustomTableFirst + 2;
vsFilterBox = vsCustomTableFirst + 3;
vsInactive = vsCustomTableFirst + 4;
vsIncSearch = vsCustomTableFirst + 5;
vsSelection = vsCustomTableFirst + 6;
// vsCustomTableLast = vsSelection;
vsHotTrack = vsCustomTableFirst + 7;
vsCustomTableLast = vsHotTrack;
考查以上幾組類的關系:
Painter和ViewInfo:
Painter類和ViewInfo類具有對應關系,在視圖元素繪制時創建出Painter類的實例,其中有多態機制的作用,下面具體了解一下這個創建過程。
在TcxCustomGridCellPainter派生的一組類中,只有它自己有構造函數:
constructor TcxCustomGridCellPainter.Create(ACanvas: TcxCanvas;
AViewInfo: TcxCustomGridCellViewInfo);
begin
inherited Create;
FCanvas := ACanvas;
FViewInfo := AViewInfo;
end;
那么當需要調用其派生類方法時,是如何構造出派生類實例的?Painter類實例都是在ViewInfo類的方法中創建出來的,代碼如下:
GetPainterClass.Create()
TcxGridDataRowViewInfo = class(TcxCustomGridRowViewInfo)
protected:
function GetPainterClass: TcxCustomGridCellPainterClass; override;
function TcxGridDataRowViewInfo.GetPainterClass: TcxCustomGridCellPainterClass;
begin
Result := TcxGridDataRowPainter;
end;
這樣,創建哪個Painter類的實例決定于ViewInfo類的實例,通過某個ViewInfo實例調用GetPainterClass.Create(),就返回對應Painter類的實例。
ViewInfo類進行繪制時,會調用Painter類的繪制方法;Painter類進行繪制時,也會調用ViewInfo類的繪制方法,比如:
procedure TcxCustomGridRecordsPainter.Paint;
var
I: Integer;
begin
with FViewInfo do
for I := 0 to Count - 1 do
with Items[I] do
if Calculated then Paint;
end;
跟蹤繪制過程可以看到,正是在兩種調用的交替中繪出了視圖的每個元素,最終在顯示設備上的繪制是由Painter類實現的,而ViewInfo的繪制方法會起到調度的作用,比如把數據行的繪制分解成各數據單元的繪制。
我們已經了解到,前一種調用是通過構造局部實例,那么后一種呢?
TcxCustomGridCellPainter中定義了FViewInfo私有成員,并將其定義為保護屬性
TcxCustomGridCellPainter = class
private
FCanvas: TcxCanvas;
FViewInfo: TcxCustomGridCellViewInfo;
protected
property ViewInfo: TcxCustomGridCellViewInfo read FViewInfo;
其派生類繼承了該屬性,并將其重新定義
TcxGridDataRowPainter = class(TcxCustomGridRowPainter)
private
function GetViewInfo: TcxGridDataRowViewInfo;
protected
property ViewInfo: TcxGridDataRowViewInfo read GetViewInfo;
function TcxGridDataRowPainter.GetViewInfo: TcxGridDataRowViewInfo;
begin
Result := TcxGridDataRowViewInfo(inherited ViewInfo);
end;
View和Styles:
視圖風格是視圖的屬性:
TcxCustomGridView = class(TcxControlChildComponent, IcxStoredObject, IcxStoredParent,
IcxGridViewLayoutEditorSupport, IcxGridViewDesignerMenu)
private
FStyles: TcxCustomGridStyles;
Protected:
property Styles: TcxCustomGridStyles read FStyles write SetStyles;
procedure TcxCustomGridView.SetStyles(Value: TcxCustomGridStyles);
begin
FStyles.Assign(Value);
end;
特定的視圖使用特定的視圖風格,以表視圖為例,可以看到兩者是如何對應的。
TcxGridTableView = class(TcxCustomGridTableView)
Published:
property Styles: TcxGridTableViewStyles read GetStyles write SetStyles;
function TcxGridTableView.GetStyles: TcxGridTableViewStyles;
begin
Result := TcxGridTableViewStyles(inherited Styles);
end;
procedure TcxGridTableView.SetStyles(Value: TcxGridTableViewStyles);
begin
inherited Styles := Value;
end;
View和LookAndFeelPainter:
ViewInfo,GridStyles和GridView類都有LookAndFeelPainter屬性,因為分組行風格設置是作用于整個視圖的,所以該屬性真正定義是在GridView中,GridStyles和ViewInfo只是返回一個引用,提供該屬性是為了方便,比如ViewInfo進行繪制時,要用到風格的設置。
function TcxCustomGridView.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;
begin
if Control = nil then
Result := TcxStandardLookAndFeelPainter
else
Result := TcxCustomGrid(Control).LookAndFeelPainter;
end;
function TcxCustomGridStyles.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;
begin
Result := GridView.LookAndFeelPainter;
end;
/* TcxGridViewHandler是視圖ViewInfo的祖先類。*/
function TcxGridViewHandler.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;
begin
Result := FGridView.LookAndFeelPainter;
end;
/* TcxCustomGridViewCellViewInfo是視圖元素ViewInfo的祖先類,FGridViewInfo是GridViewInfo屬性的成員變量。*/
function TcxCustomGridViewCellViewInfo.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;
begin
Result := FGridViewInfo.LookAndFeelPainter;
end;