﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-依旧的博客-文章分类-编程</title><link>http://www.cppblog.com/zliner/category/1639.html</link><description>技术学习</description><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 08:18:39 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 08:18:39 GMT</pubDate><ttl>60</ttl><item><title>cxGrid源代码结构分析Ⅰ(视图绘制)</title><link>http://www.cppblog.com/zliner/articles/24165.html</link><dc:creator>依旧的博客</dc:creator><author>依旧的博客</author><pubDate>Tue, 15 May 2007 10:05:00 GMT</pubDate><guid>http://www.cppblog.com/zliner/articles/24165.html</guid><wfw:comment>http://www.cppblog.com/zliner/comments/24165.html</wfw:comment><comments>http://www.cppblog.com/zliner/articles/24165.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zliner/comments/commentRss/24165.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zliner/services/trackbacks/24165.html</trackback:ping><description><![CDATA[&nbsp;
<p align=left><span>视图用来表现数据，也是用户接口。当数据更新时，视图应该随之改变，在交互过程中，视图需要响应用户，这些情况下都会引起视图的绘制。</span><span> cxGrid</span><span>可以用多种视图表现关系型数据，最常用的是表格视图，我们以表格视图作为默认的对象，分析</span><span>cxGrid</span><span>用以实现视图绘制的基本结构。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>表格视图按行，列布局，行优先顺序绘制，绘制的基本元素是行和单元</span><span>(cell)</span><span>。由于数据内容的动态性，行是动态生成的。表格视图提供了各种可定制性，包括可选的分组行风格和若干自定义风格，这些复杂特性背后有很好的设计。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>视图绘制相关的几组类：</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>ViewInfo</span></strong><strong><span>类族：</span></strong></p>
<p align=left><span>描述视图元素的绘制信息，视图元素要绘制成什么样子，完全由其</span><span>ViewInfo</span><span>确定。祖先类是</span><span>TcxCustomGridCellViewInfo</span><span>，数据行，数据单元，分组行等视图元素以及视图本身都有相应的派生类。</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Painter</span></strong><strong><span>类族：</span></strong></p>
<p align=left><span>按照</span><span>ViewInfo</span><span>，在画布上绘制视图元素。祖先类是</span><span>TcxCustomGridCellPainter</span><span>。</span><span>&nbsp;TcxCustomGridCellPainter = class</span></p>
<p align=left><span>&nbsp;private</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; FCanvas: TcxCanvas;</span></p>
<p align=left><span>FViewInfo: TcxCustomGridCellViewInfo;</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>View</span></strong><strong><span>类族：</span></strong></p>
<p align=left><span>整个视图的描述，包括了各种设置信息。祖先是</span><span>TcxCustomGridView</span><span>。</span></p>
<p align=left><span>View</span><span>和</span><span>ViewInfo</span><span>的不同在</span><span>ViewInfo</span><span>描述绘制信息，而</span><span>View</span><span>描述设置信息，</span><span>ViewInfo</span><span>是动态构造的，当</span><span>Grid</span><span>创建时，如果有一个分组多条记录，那么每条记录会生成一个</span><span>ViewInfo</span><span>实例，如果收起分组，这些实例将被销毁，展开分组，会再次生成每条记录的</span><span>ViewInfo</span><span>实例，而一个表格视图始终只有一个实例。</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>LookAndFeelPainter</span></strong><strong><span>类族：</span></strong></p>
<p align=left><span>用于进行有关分组行风格的绘制。祖先是</span><span>TcxCustomLookAndFeelPainter</span><span>。</span></p>
<p align=left><span>绘制视图元素时，涉及到分组行风格</span><span>(GroupRowStyle)</span><span>的绘制任务，都被委托给</span><span>LookAndFeelPainter</span><span>类的实例，由此实现多态的风格。</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Style</span></strong><strong><span>和</span></strong><strong><span>Styles</span></strong><strong><span>类族：</span></strong></p>
<p align=left><span>Style</span><span>类的祖先是</span><span>TcxCustomStyle</span><span>，</span><span>Styles</span><span>类的祖先是</span><span>TcxCustomStyles</span><span>。</span><span>TcxCustomStyle</span><span>类表示一种自定义风格，</span><span>TcxCustomStyles</span><span>类表示一组风格。</span><span>TcxCustomStyles</span><span>内部用一个</span><span>map</span><span>保存这些风格，给出键，可通过</span><span>Values</span><span>属性取出指定的风格。</span></p>
<p align=left><span>TcxCustomStyles = class(TcxInterfacedPersistent, IcxStyleChangeListener)</span></p>
<p align=left><span>public</span></p>
<p align=left><span>property Values[Index: Integer]: TcxCustomStyle read GetValue write SetValue;</span></p>
<p align=left><span>键的取值范围如下：</span></p>
<p align=left><span>&nbsp;vsCustomTableFirst = vsCustomLast + 1;</span></p>
<p align=left><span>&nbsp;vsContent = vsCustomTableFirst;</span></p>
<p align=left><span>&nbsp;vsContentEven = vsCustomTableFirst + 1;</span></p>
<p align=left><span>&nbsp;vsContentOdd = vsCustomTableFirst + 2;</span></p>
<p align=left><span>&nbsp;vsFilterBox = vsCustomTableFirst + 3;</span></p>
<p align=left><span>&nbsp;vsInactive = vsCustomTableFirst + 4;</span></p>
<p align=left><span>&nbsp;vsIncSearch = vsCustomTableFirst + 5;</span></p>
<p align=left><span>&nbsp;vsSelection = vsCustomTableFirst + 6;</span></p>
<p align=left><span>//&nbsp;vsCustomTableLast = vsSelection;</span></p>
<p align=left><span>&nbsp;vsHotTrack = vsCustomTableFirst + 7;</span></p>
<p align=left><span>&nbsp;vsCustomTableLast = vsHotTrack;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>考查以上几组类的关系：</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Painter</span></strong><strong><span>和</span></strong><strong><span>ViewInfo</span></strong><strong><span>：</span></strong></p>
<p align=left><strong>&nbsp;</strong></p>
<p align=left><span>Painter</span><span>类和</span><span>ViewInfo</span><span>类具有对应关系，在视图元素绘制时创建出</span><span>Painter</span><span>类的实例，其中有多态机制的作用，下面具体了解一下这个创建过程。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>在</span><span>TcxCustomGridCellPainter</span><span>派生的一组类中，只有它自己有构造函数：</span></p>
<p align=left><span>constructor TcxCustomGridCellPainter.Create(ACanvas: TcxCanvas;</span></p>
<p align=left><span>&nbsp;AViewInfo: TcxCustomGridCellViewInfo);</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;inherited Create;</span></p>
<p align=left><span>&nbsp;FCanvas := ACanvas;</span></p>
<p align=left><span>&nbsp;FViewInfo := AViewInfo;</span></p>
<p align=left><span>end;</span></p>
<p align=left><span>那么当需要调用其派生类方法时，是如何构造出派生类实例的？</span><span>Painter</span><span>类实例都是在</span><span>ViewInfo</span><span>类的方法中创建出来的，代码如下：</span></p>
<p align=left><span>GetPainterClass.Create()</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>TcxGridDataRowViewInfo = class(TcxCustomGridRowViewInfo)</span></p>
<p align=left><span>protected:</span></p>
<p align=left><span>function GetPainterClass: TcxCustomGridCellPainterClass; override;</span></p>
<p align=left>&nbsp;</p>
<p align=left>&nbsp;</p>
<p align=left><span>function TcxGridDataRowViewInfo.GetPainterClass: TcxCustomGridCellPainterClass;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;Result := TcxGridDataRowPainter;</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>这样，创建哪个</span><span>Painter</span><span>类的实例决定于</span><span>ViewInfo</span><span>类的实例，通过某个</span><span>ViewInfo</span><span>实例调用</span><span>GetPainterClass.Create()</span><span>，就返回对应</span><span>Painter</span><span>类的实例。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>ViewInfo</span><span>类进行绘制时，会调用</span><span>Painter</span><span>类的绘制方法；</span><span>Painter</span><span>类进行绘制时，也会调用</span><span>ViewInfo</span><span>类的绘制方法，比如：</span></p>
<p align=left><span>procedure TcxCustomGridRecordsPainter.Paint;</span></p>
<p align=left><span>var</span></p>
<p align=left><span>&nbsp;I: Integer;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;with FViewInfo do</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; for I := 0 to Count - 1 do</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with Items[I] do</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Calculated then Paint;</span></p>
<p align=left><span>end;</span></p>
<p align=left><span>跟踪绘制过程可以看到，正是在两种调用的交替中绘出了视图的每个元素，最终在显示设备上的绘制是由</span><span>Painter</span><span>类实现的，而</span><span>ViewInfo</span><span>的绘制方法会起到调度的作用，比如把数据行的绘制分解成各数据单元的绘制。</span></p>
<p align=left><span>我们已经了解到，前一种调用是通过构造局部实例，那么后一种呢</span><span>?</span></p>
<p align=left><span>TcxCustomGridCellPainter</span><span>中定义了</span><span>FViewInfo</span><span>私有成员，并将其定义为保护属性</span></p>
<p align=left><span>&nbsp;TcxCustomGridCellPainter = class</span></p>
<p align=left><span>&nbsp;private</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; FCanvas: TcxCanvas;</span></p>
<p align=left><span>FViewInfo: TcxCustomGridCellViewInfo;</span></p>
<p align=left><span>&nbsp;protected</span></p>
<p align=left><span>property ViewInfo: TcxCustomGridCellViewInfo read FViewInfo;</span></p>
<p align=left><span>其派生类继承了该属性，并将其重新定义</span></p>
<p align=left><span>&nbsp;TcxGridDataRowPainter = class(TcxCustomGridRowPainter)</span></p>
<p align=left><span>&nbsp;private</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; function GetViewInfo: TcxGridDataRowViewInfo;</span></p>
<p align=left><span>&nbsp;protected</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; property ViewInfo: TcxGridDataRowViewInfo read GetViewInfo;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>function TcxGridDataRowPainter.GetViewInfo: TcxGridDataRowViewInfo;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;Result := TcxGridDataRowViewInfo(inherited ViewInfo);</span></p>
<p align=left><span>end;</span></p>
<p align=left><strong>&nbsp;</strong></p>
<p align=left><strong><span>View</span></strong><strong><span>和</span></strong><strong><span>Styles</span></strong><strong><span>：</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>视图风格是视图的属性：</span></p>
<p align=left><span>&nbsp;TcxCustomGridView = class(TcxControlChildComponent, IcxStoredObject, IcxStoredParent,</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; IcxGridViewLayoutEditorSupport, IcxGridViewDesignerMenu)</span></p>
<p align=left><span>&nbsp;private</span></p>
<p align=left><span>FStyles: TcxCustomGridStyles;</span></p>
<p align=left><span>&nbsp;Protected:</span></p>
<p align=left><span>property Styles: TcxCustomGridStyles read FStyles write SetStyles;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>procedure TcxCustomGridView.SetStyles(Value: TcxCustomGridStyles);</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;FStyles.Assign(Value);</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>特定的视图使用特定的视图风格，以表视图为例，可以看到两者是如何对应的。</span></p>
<p align=left><span>TcxGridTableView = class(TcxCustomGridTableView)</span></p>
<p align=left><span>Published:</span></p>
<p align=left><span>property Styles: TcxGridTableViewStyles read GetStyles write SetStyles;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>function TcxGridTableView.GetStyles: TcxGridTableViewStyles;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;Result := TcxGridTableViewStyles(inherited Styles);</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>procedure TcxGridTableView.SetStyles(Value: TcxGridTableViewStyles);</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;inherited Styles := Value;</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>View</span></strong><strong><span>和</span></strong><strong><span>LookAndFeelPainter</span></strong><strong><span>：</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>ViewInfo</span><span>，</span><span>GridStyles</span><span>和</span><span>GridView</span><span>类都有</span><span>LookAndFeelPainter</span><span>属性，因为分组行风格设置是作用于整个视图的，所以该属性真正定义是在</span><span>GridView</span><span>中，</span><span>GridStyles</span><span>和</span><span>ViewInfo</span><span>只是返回一个引用，提供该属性是为了方便，比如</span><span>ViewInfo</span><span>进行绘制时，要用到风格的设置。</span></p>
<p align=left><span>function TcxCustomGridView.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;if Control = nil then</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; Result := TcxStandardLookAndFeelPainter</span></p>
<p align=left><span>&nbsp;else</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; Result := TcxCustomGrid(Control).LookAndFeelPainter;</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>function TcxCustomGridStyles.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;Result := GridView.LookAndFeelPainter;</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>/* TcxGridViewHandler</span><span>是视图</span><span>ViewInfo</span><span>的祖先类。</span><span>*/</span></p>
<p align=left><span>function TcxGridViewHandler.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;Result := FGridView.LookAndFeelPainter;</span></p>
<p align=left><span>end;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>/* TcxCustomGridViewCellViewInfo</span><span>是视图元素</span><span>ViewInfo</span><span>的祖先类，</span><span>FGridViewInfo</span><span>是</span><span>GridViewInfo</span><span>属性的成员变量。</span><span>*/</span></p>
<p align=left><span>function TcxCustomGridViewCellViewInfo.GetLookAndFeelPainter: TcxCustomLookAndFeelPainterClass;</span></p>
<p align=left><span>begin</span></p>
<p align=left><span>&nbsp;Result := FGridViewInfo.LookAndFeelPainter;</span></p>
<p align=left><span>end;</span></p>
<img src ="http://www.cppblog.com/zliner/aggbug/24165.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zliner/" target="_blank">依旧的博客</a> 2007-05-15 18:05 <a href="http://www.cppblog.com/zliner/articles/24165.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>