CnClasses开发包基础类.txt 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. ======================================================================
  2. CnClasses 开发包基础类单元
  3. ======================================================================
  4. by 周劲羽 (zjy@cnpack.org) 2002.07.09
  5. CnClasses 单元包含公共的最底层基础类实现。
  6. 该单元位于开发包Source/Common目录下。
  7. ----------------------------------------------------------------------
  8. TCnPersistent
  9. ----------------------------------------------------------------------
  10. TCnPersistent <-- TPersistent
  11. 带更新通知的持久性类,派生自 TPersistent,主要扩充了更新通知、计数等功
  12. 能。
  13. TCnPersistent = class(TPersistent)
  14. protected
  15. procedure Changing; virtual;
  16. procedure Changed; virtual;
  17. function GetOwner: TPersistent; override;
  18. function IsUpdating: Boolean;
  19. procedure OnChildChanging(Sender: TObject); virtual;
  20. procedure OnChildChange(Sender: TObject); virtual;
  21. procedure SetUpdating(Updating: Boolean); virtual;
  22. property Owner: TPersistent;
  23. public
  24. constructor Create; overload; virtual;
  25. constructor Create(AOwner: TPersistent); overload;
  26. constructor Create(ChangeProc: TNotifyEvent); overload;
  27. constructor Create(ChangingProc, ChangeProc: TNotifyEvent);
  28. overload;
  29. procedure BeginUpdate; virtual;
  30. procedure EndUpdate; virtual;
  31. published
  32. property OnChanging: TNotifyEvent;
  33. property OnChange: TNotifyEvent;
  34. end;
  35. 1. 更新通知
  36. ------------
  37. 在面向对象的系统中,对属性的赋值经常会引发一个操作,比如更改标签的
  38. Caption、Font 等属性都会使标签重绘。通常,控件使用一个通用方法来处理大
  39. 部分的属性变更事件,最常见的是在 Paint 方法根据当前属性重绘控件,而属
  40. 性写方法中则用 Invalidate 通知控件重绘。
  41. 作为提高组件易用性的一种手段,我们经常把一些相关的属性打包到一起,再为
  42. 它编写属性编辑器,有时还会有多重嵌套,这样会使得属性通知变得复杂,
  43. TCnPersistent通过定义以下成员以描述这种共性:
  44. protected
  45. procedure Changing; virtual;
  46. 开始变更,通常在一个较长的操作中调用,如果当前更新记数为0,将产生
  47. OnChanging事件。
  48. procedure Changed; virtual;
  49. 内容已变更,指示某个属性内容已发生变化,如果当前更新记数为0,将产
  50. 生OnChange事件。一般用在属性写方法中。
  51. procedure OnChildChanging(Sender: TObject); virtual;
  52. 子属性开始变更事件处理代码,默认操作同Changing,但传递子属性为
  53. Sender。
  54. procedure OnChildChange(Sender: TObject); virtual;
  55. 子属性内容已变更事件处理代码,默认操作同Changed,但传递子属性为
  56. Sender。
  57. public
  58. constructor Create(ChangeProc: TNotifyEvent); overload;
  59. 这个构造器允许传递一个方法来给OnChange事件赋值。
  60. constructor Create(ChangingProc, ChangeProc: TNotifyEvent);
  61. overload;
  62. 这个构造器允许传递两个方法来给OnChanging和OnChange事件赋值。
  63. published
  64. property OnChanging: TNotifyEvent;
  65. 属性开始更新事件。
  66. property OnChange: TNotifyEvent;
  67. 属性已变更事件。
  68. 2. 更新计数
  69. -----------
  70. 有时候,用户会批量设置属性,如果每设置一个属性都引发控件进行大量的处理,
  71. 将使得运行速度变慢,一般采用更新计数的方法来解决:
  72. protected
  73. function IsUpdating: Boolean;
  74. 正在更新标志,表示当前有一个以上项目正在更新。
  75. procedure SetUpdating(Updating: Boolean); virtual;
  76. 更新状态变化处理方法,默认的处理是当Updating为True即开始进入更新状
  77. 态时调用Changing方法,反之表示更新结束,调用Changed方法。
  78. public
  79. procedure BeginUpdate; virtual;
  80. 开始更新,增加更新计数,当更新计数大于0时,对Changing和Changed方法
  81. 的调用不产生相关事件。使用时必须与EndUpdate成对使用,并用
  82. try...finally..end保护。嵌套调用该方法时仅第一次调用
  83. SetUpdating(True)。
  84. procedure EndUpdate; virtual;
  85. 结束更新,减少更新计数,必须与BeginUpdate成对使用,嵌套调用该方法
  86. 时仅最后一次调用SetUpdating(False)。
  87. 3. 提供Owner属性
  88. ----------------
  89. (该设计思想由开发组 何清 兄提供)
  90. 在某些特殊场合,IDE需要获取类属性的Owner以获得一个完整的命名路径,如
  91. TCollection派生类要在设计期有效,必须提供Owner属性。Delphi提供了
  92. TOwnedCollection来完成该功能,而如果一个TCollection派生类在组件的类属
  93. 性甚至多重类属性中,则它的直接和间接拥有者都应该提供Owner属性,使得IDE
  94. 可以获得一个类似ComponentName.Property1.Property2.Collection这样的命名
  95. 路径来唯一标识该TCollection派生类实例及其子项。如果不这样做,你会发现
  96. 在设计期你无法使用TCollection派生类属性的属性编辑器。
  97. TCnPersistent提供以下解决方案:
  98. protected
  99. function GetOwner: TPersistent; override;
  100. 重载了TPersistent的GetOwner方法,返回Owner属性,子类可不再关心。
  101. property Owner: TPersistent;
  102. 允许子类在需要的时候设置实例的Owner属性,支持读写操作。
  103. public
  104. constructor Create(AOwner: TPersistent); overload;
  105. 类构造器,支持Owner参数,
  106. ----------------------------------------------------------------------
  107. TCnThreadPersistent
  108. ----------------------------------------------------------------------
  109. TCnThreadPersistent <-- TCnPersistent <-- TPersistent
  110. 线程安全的更新通知持久性类,增加了线程安全的控制代码。
  111. VCL本身并不是线程安全的,如果多个线程同时访问一个控件时,很容易引发错
  112. 误。我们知道,TThread提供了一个Synchronize,利用一种巧妙的方法将线程方
  113. 法通过消息发送到进程的主线程中执行,以获得访问VCL时的同步。而
  114. TCnThreadPersistent主要是为解决并发访问数据时的冲突而设计,该类的设计
  115. 主要参考了TCanvas的实现方法:
  116. TCnThreadPersistent = class(TCnPersistent)
  117. protected
  118. property LockCount: Integer;
  119. 当前加锁计数,只读属性
  120. public
  121. procedure Lock;
  122. 加锁,增加加锁计数,进入临界访问区,以避免访问冲突。该方法必须与
  123. Unlock成对使用,并用try...finally..end保护。
  124. function TryLock: Boolean;
  125. 尝试加锁,如果当前LockCount为0,则加锁,否则放弃。返回成功标志,如
  126. 果成功,用户应负责解锁。
  127. procedure Unlock;
  128. 解锁,减少加锁计数,离开临界访问区。该方法必须与Lock成对使用。
  129. end;
  130. 需要注意的是,使用了TCnThreadPersistent派生类的代码并不表明它就是线程
  131. 安全的。线程安全性需要由用户自己来保证,TCnThreadPersistent只是提供了
  132. 实现的方法而已。如果有一段数据处理代码允许在多线程中使用,并且不允许在
  133. 执行的过程中被其它线程重入,用户应该用下面的方法来保护这段代码:
  134. bgein
  135. CnThreadPersistent.Lock;
  136. try
  137. ... // 需要保护的代码
  138. finally
  139. CnThreadPersistent.Unlock;
  140. end;
  141. end;
  142. ----------------------------------------------------------------------
  143. TCnComponent
  144. ----------------------------------------------------------------------
  145. TCnComponent <-- TComponent <-- TPersistent
  146. CnPack不可视组件基类,当前仅增加了版权信息功能,这些信息用在组件的关于
  147. 窗口中。
  148. TCnComponent = class(TComponent)
  149. protected
  150. function GetAuthorCount: Integer; virtual;
  151. 取组件作者数,重载该方法返回组件作者总数,默认为0
  152. function GetAuthor(Index: Integer): string; virtual;
  153. 取组件作者函数,参数为作者索引号(从0开始),重载该方法返回组件作
  154. function GetEmail(Index: Integer): string; virtual;
  155. 取组件作者邮箱函数,参数为作者索引号(从0开始),重载该方法返回组
  156. 件作者邮箱
  157. function GetComment: string; virtual;
  158. 取组件注释函数,组件重载该方法返回组件注释
  159. published
  160. property About: TCnCopyright;
  161. 组件的关于属性,注册有属性编辑器,用于显示版权信息。
  162. end;