万星星@豌豆荚 欢迎加入我们
一个吃软饭的男人!!!!!我只想写程序####
微博:http://weibo.com/wanlianwen
posts - 172,  comments - 1253,  trackbacks - 0

最近工作上比较忙,加之编码任务较多,没来得及继续之前的讲解。抽出时间把这最重要的一部分东西做个阐述。行文以基本的编程思维及个人思考过程为线索。

 

众所周知,RichEdir强大在于其图文混排(在这里不跟Word、HTML比),其中的图替换为动态图的核心问题就归结于如何高效刷新。我们知道GDI操作是最消耗CPU的,所以刷新整个RichEdit窗口是不可取的,其副作用会导致更严重的闪烁问题。解决问题的思路很简单:类似于拖拽时候在屏幕绘制异或线,我们的动画重绘时不请求RichEdit,而直接在其窗口的DC上绘制当前动画帧,此时缺少是如何确定该OLE的位置,这个是所有问题的关键。先看下面这幅图:

 

假定1-5全部都是GIF图片,非GIF可以暂时无视,这个后面大家会非常清楚如何处理。在这个过程中,2不见了,而4是新出现的。对于4新出现时,RichEdit自身肯定会触发其:

Draw(
    DWORD dwDrawAspect, LONG lindex, void* pvAspect,
    DVTARGETDEVICE* ptd, HDC hicTargetDev, HDC hdcDraw,
    LPCRECTL prcBounds, LPCRECTL prcWBounds,
    BOOL (__stdcall *pfnContinue)(DWORD_PTR dwContinue),
    DWORD_PTR dwContinue)

 

这个时候,我们知道新的GIF图片进入可视区,可以把它添加到集合中。对于2的动画触发时间到来时,我们可以确定其位置且与可视区比对,发现其不再可视区,则从集合中移除。这样就可以得到一个接近于(略大于)当前视口中的动画控件集合,当有新的动画触发时间到来时,我们可以先检查其是否在可视区,如果不在则不用GDI操作,仅仅更新其当前帧。当然这些工作你也可以不做,但是在动画控件数量大的时候效率可能略有下降,主要是查找的过程(索引、位置)比较耗时。

 

如何确定一个OLE的位置呢?由于我们插入OLE都使用了REO_BELOWBASELINE标志,也就是跟当前行的底部对齐,所以OLE左下角位置的精确度对我们来说很重要。看下图:

假设图中黑框是一个OLE对象,其字符索引为CPN,假定第N+1行的第一个字符索引为CPN1,那么OLE左下角坐标={PosFromChar(CPN).x, PosFromChar(CPN1).y },PosFromChar这个是RichEdit提供的。问题的关键是最后一行怎么计算?此时没有第N+1行。对于这种特殊情况,主要是Y坐标的计算,可以这样考虑:Y=RichEdit内容高度-滚动条位置。猜测: 计算内容高度可能比较耗时,故QQ的聊天消息显示部分强制在底部加了一行,以避免这种情况出现。

 

得到左下角位置以后,可能你会觉得就万事大吉了。错!还有一个关键点!我们可以通过OLE的接口GetExtent得到其大小,然而这个大小没有考虑缩放比例,所以你需要根据当前缩放比例进行计算,而这个计算牵扯到浮点数运算,过程中的来回不仅麻烦而且不精确,所以OLE的可视大小要想非常精确是不能通过计算来的。我们前面知道OLE绘制的时候会传入可视范围,假如我们保存下来是不是就可以解决问题了呢?当然,显然,你可以试试!

这些问题主要原因是RichEdit的很多接口方法没有暴露,而Win8的SDK会做重大升级,很多之前的问题都会变成不是问题,或许还会引起更多的新特性,但是动画本身的逻辑还是需要自己实现,或者会简单许多,至于多少我还尚不清楚,但是目前来看这种方案效率足够! 

 

到了这里,核心技术应该大白天下,整个过程,我追求了位置的精准度,并据此获得最小可视集合进行刷新优化。

 

最新SDK&Demo,参见:http://code.google.com/p/im-solution/。希望你会喜欢!

posted on 2012-09-08 18:10 万连文 阅读(4400) 评论(16)  编辑 收藏 引用 所属分类: 小作品richedit

FeedBack:
# re: richedit研究06 – 高效动画刷新
2012-09-08 19:09 | iunkown
问一下,GIF对应的IOleInPlaceSite::GetWindowContext 取到的位置是否准确?为什么要用GetExtent呢?

我的一个实验DEMO的SOURCE CODE如下,
http://www.cppblog.com/Files/mcs51a/GifDisplayCtrl.rar

DEMO中代码比较偷懒,可能有不准确的地方  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-08 19:39 | 万连文
@iunkown
这个我没有测试过,也没有考虑过,不过确实是一种思路,你可以自己确认。但是我的方法未尝不是好方法,不是么?


后来我看了你的东西,觉得就是前面说的毫无章法,无头苍蝇。你的那个链接我看了,连运行一下的心情都木有。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-08 20:04 | 路障
呵呵,万大侠,我之前以为你用了OLE接口的其它方法刷新的,原来也是直接在DC上面绘制的。

我还想问个问题,当你在DC上面绘制GIF帧的时候,你如何获取RichEdit的背景颜色或者背景图片?因为自己直接在DC上面绘制时,是不会像在OLE接口的Draw()函数里面那样,已经由系统先绘制了背景的。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-08 20:06 | 万连文
@路障
看我的Demo,看我的接口,你就会发现我是怎么做的!!给我点面子呗。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-09 11:30 | Loaf
一直RSS,博主非常高产啊……  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-09 12:32 | 万连文
@Loaf
其实我非常少做项目,很多工作时间用来搞这些兴趣。

我个人表示对RSS不太了解,有点土鳖。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-09 15:50 | 路障
@万连文

万大侠,之前的评论绝对没有取笑的意思。还是多亏了万大侠,提供了这么多篇网上几乎没有详细讲的教程,使我们受益良多。否则还要走更多的弯路呢。继续膜拜万大侠。
  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-12 14:07 | M77
@Loaf

google Reader的RSS链接出现错误了
  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-12 14:09 | M77
@万连文
楼主这SDK头文件写得很有Google的范  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2012-09-12 14:28 | 万连文
@M77
过奖,回头一看又发现几个不标准的地方,努力遵守Google规范。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2013-01-05 03:28 | 程旭
慨叹天下文章一大抄,天下程序也是一大抄,就看你怎么抄,抄的有没有思想,呵呵。老万研究很透彻,尽管描述不适合初学者,但是非常不错了。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2013-01-05 20:36 | 程旭
全部重建感觉放弃ATL太浪费,尽管Ctrl键按的次数不多,呵呵。重建了Create其他可以沿用ATL也可以,这方面效率没影响。绘制方法对效率可差万倍。所以重点还是对richedit的扩展,STL使用必不可少,不嫌费事当然可以自己写链表之类的。不知 万老师 现在又开始研究什么新东西了?  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2013-01-05 22:54 | 万连文
@程旭
最近这几个月从研究webkit,转向虚拟机字节码,然后有转向IDA OD学习,比较闲散自由无目的,但是没有偷懒就好。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2013-01-07 01:16 | 程旭
@万连文
IDA对没加密的很好用,OD对付加密的绝佳。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2013-01-11 07:14 | 程旭
600动态表情同时显示,CPU占用1%也许0%。  回复  更多评论
  
# re: richedit研究06 – 高效动画刷新
2013-05-21 16:25 | 杨潇
我来这里是为了感谢博主@万连文 的。博主提供了从动画OLE类要实现的接口,到如何精确地找出需重绘的动画这一整套信息,在思路上的参考价值再怎么高估也不过分。

同时,通过对微软WindowlessRE项目的参考,我终于成功地将无窗口模式的RichEdit、RichEdit动画控件集成到了我们内部自己实现的DirectUI界面之中。

万大侠提供的思路让我节省了大量时间,少走了N多弯路。

再次谢谢万大侠的分享!
  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


简历下载
联系我

<2012年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

常用链接

留言簿(66)

随笔分类

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜