说说GUI中的”鹰眼”技术

        所谓鹰眼,通俗的讲就是小地图,玩过星际争霸的都知道,它的主界面左下角就是小地图,它的主要功能是让人瞥上一眼就能大体了解整个的战场的地形和敌我力量分布,而且能利用小地图在整个战场上快速的移动视角,因此在很多游戏中鹰眼的作用很大。

       在GUI程序中,鹰眼也是类似的作用。它能显示全部文档的大概的结构,而且能利用它来快速的在文档中移动视角。很多商业的GUI程序,特别是设计器类的程序,都提供了鹰眼功能。

       鹰眼的结构一般是在一个显示区域的中间,显示了整个文档的缩小的视图,一般的为了性能,采用整个文档的缩小的预览图片来显示。然后在这个小视图上使用一个方框或者其他手段来突出显示其中的一部分,而这一部分代表了当前主视图区域在整个文档中的位置和大小。当主视图区域进行滚动时,鹰眼中突出显示的区域也会移动。当用户用鼠标在鹰眼区域中点击或拖拽方式改变突出显示区域的位置时,主视图区也会做相应的滚动。当整个文档的内容发生大的改变时,鹰眼中文档预览BMP图片也会更新。

       现在说说本人实现鹰眼的过程。

       首先准备文档预览BMP图片,该图片要求大小合适,不能过大或过小。根据鹰眼区域的大小和整个文档从长宽比获得合适的图片大小,算出缩小比例,这个比例很重要,需要妥善保存。然后创建一个 System.Drawing.Bitmap 对象,再使用 System.Drawing.Graphics.FromImage 创建一个Graphics 对象,调用 Graphics.ScaleTransfrom 来设置缩小比例,然后使用个Graphics绘制整个文档内容,绘制过程和正常在视图区域中绘制没什么区别。为了提高性能,当缩小比例很小时,有些比较小的文档元素不必绘出,也不必绘制文本,此时需要靠缩小比例来进行判断了。

       当用户改变的文档内容时,应该考虑更新鹰眼的预览BMP图片了,当改变量相对于整个文档来说不大时,不必更新,若改变量比较大时需要更新预览BMP图片了,为了提高性能,每一次改变文档时都将改变区域的面积和整个文档的面积进行比较,若两者比率超过某个设定的值时,就进行更新,否则不必更新。

       获得预览BMP图片后,将其放置在鹰眼区域的中间。然后根据主视图区域的大小( Control.ClientSize )和预览图片的缩小率获得其在鹰眼中的映射区域的大小,根据主视图区域在整个文档中的位置获得其映射位置在预览图片中的位置,如此就可确定主视图区域在预览图片中的映射区域的位置和大小,每次重绘鹰眼区域时就可以突出显示映射区域了。主视图区域每次进行滚动后都需要重新计算映射区域的位置并立即重绘鹰眼区域。若仅简单的使用Control.Invalidate声明鹰眼区域无效时会导致更新不及时,影响效果。由于鹰眼区域不大,绘制操作简单,在此我简单的使用Control.Refresh进行全部绘制。

       由于映射区域的大小是基于主视图区域的客户区大小的,因此当主视图区域大小发生改变时也需要更新鹰眼,可以在主视图区域的Resize事件中进行处理。

       在XDesigner中,本人不是使用整个文档的大小来计算映射区域的大小,而是使用文档中包含所有内容的外接矩形来计算映射区域的大小,没什么很特别的原因,个人做法而已。

       .NETUserControl没有提供滚动事件,因此需要重载它的WnProc成员方法来进行增强,当WnProc方法传入的参数表示滚动消息时就触发一个滚动事件,而主程序就可响应这个事件来更新鹰眼了。

       当用户在鹰眼中用鼠标点击或托拽操作来改变突出显示区域时,根据突出显示区域的位置和预览图片缩小率算出主视图区域在整个文档中的位置,然后调整主视图区域的滚动位置即可(使用属性 AutoScrollPosition )。在XDesigner中,当用户在预览图片中鼠标按下时,程序会移动映射区域位置使得鼠标按下时的位置为映射区域的中心,然后调整映射区域使之全部在预览图片中。然后滚动主视图区域。当鼠标按下后的鼠标移动事件中,鼠标移动多少则映射区域移动多少,然后相应的滚动主视图区域。

       当主视图区域本身进行了缩放处理,则此时主视图区域和鹰眼中映射区域间会有两个缩放比率,此时坐标转换则多了一次处理。

    以上是本人对鹰眼的理解和实现,相信还有更好的方法,望高手指点。

posted on 2006-04-20 10:44  袁永福 电子病历,医疗信息化  阅读(2959)  评论(9编辑  收藏  举报

导航