3.避免无谓的重绘
从技术上讲,在无效的区域外绘制是无害的(因为不管是不是在控件的边界之内,窗口服务器都会将此类绘制剪裁掉),但这是一种潜在的浪费。通过将绘制行为限制在无效区域之内能够节省时间。付出的代价是,必须进行某些测试,找出哪些必须绘制,哪些不必绘制。
这就是传递给Draw()函数的TRect的目的:它是无效区域的限制矩形。如果愿意,可以用它只绘制(或重绘)在传递的 TRect内部的控件部分。如果避免无关绘制节省的开销大于测试的开销,那么值得这样做。
实践中,仅仅通过将控件的重绘活动完全限制在限制矩形之内只能获得很少的增益:重绘整个控件比较简单,而且并不会慢很多。因此,编写大多数控件时,忽略传递的限制矩形。如果编写确实要使用 TRect的控件,记住仍然要遵守覆盖控件内部的整个无效区域、并且绝不在控件之外绘制的约定(但是如果使用窗口服务器的某个功能,那么需要绘制整个矩形区域而不仅仅是无效区域)。可能仍然需要设置剪裁区域来确保这一点—系统没有为我们设置。
在Symbian操作系统发展的早期,我们将无效区域(而不是限制矩形)传递给Draw()。结果证明,这样做得不偿失。这些区域是任意大小的数据结构,传递它们比传递 TRect 要难得多,但不管是不是需要 —通常并不需要,都必须传递它们。作为折衷方案,我们传递无效区域的限制矩形。
4.打破const和异常退出规则
在极少数情形下,可能需要在Draw()中做某些非绘图的处理。举例来说,如果视图非常复杂,为使用最少内存,而对某些关联的数据结构进行延迟初始化(lazy initialization),此时就会发生这种情况。
在这种情形下,可能需要在Draw()期间进行内存分配,以保持与绘制相关的中间计算结果,而内存分配可能导致异常退出。此外,在控件中可能想要使用一个指针来引用新分配的内存。这将要求改变指针的值,它会破坏Draw()的常量性。
这种情况的解决办法是,使用强制转换来除掉常量性(需要更多MUTABLE宏的信息,参考SDK),并将资源分配代码放到一个可能发生异常退出的函数里,该函数从Draw()中的TRAP()内调用。如果资源分配失败,同样必须确定要绘制什么。
【责任编辑:
董书 TEL:(010)68476606】