==========================================================================
补充:
(1)为了在预览图中显示动态的 GIF 图片,我舍弃了 CImage, 而引用了 CxImage 类库的代码。这样可以看到动态的 GIF 动画。
(2)改进了绘制方法,改为使用内存位图绘制,并把 WM_ERASEBKGND 合并到 WM_PAINT 中,以降低闪烁。
(3)修改了鼠标位于表情网格(Cells)的最右边缘时,错误的认为选中表情是下一行的第一个 Cell 的BUG。该 BUG 会导致鼠标在
最右侧移入移出时在右上角有强烈闪烁感。
--hoodlum1980 2010年1月29日
==========================================================================
最近有好多篇帖子是关于QQ的选择表情的那个窗口实现的。最初以为这是一个比较简单的功能,不过做起来还是发现做了整个一晚上才做的差不多做好。做完我想为什么有很多人愿意尝试它呢?可能是基于它的那个“预览图”对鼠标的“躲藏”功能是它的一个亮点,所以可能是因为这个原因引起很多人的兴趣来实现它。前人已经采用了很多种方式实现,例如 C# 的 winform,等等。在这里是使用 VC 实现的。在这个范例中也展示了如何定制一个特殊外观的窗口,以及自定义绘制(OWNER DRAW)按钮(1/2,上一页,下一页按钮),如何遍历一个文件夹下的所有文件等基本方法。
不过这个例子仅仅是模仿QQ的UI,实际上这也是这个例子的唯一意义。由于VC里面对于存在多帧的 gif 格式并没有特别好的支持,包括 CImage 尽管支持大多数图像格式,但是却仅能加载 gif 的一帧,而要展示动画形式的gif,则通常要求助于第三方代码,例如 CxImage 等。因此这里我就仅仅模拟这个界面,实际上在预览框里面我仅仅绘制一下而已。而并没有去真正的做 gif 动画的预览。
当鼠标在窗口上移动时,需要绘制一个蓝色小边框反应当前选中的是哪一个cell,而且预览图会尽可能惰性的“远离”鼠标。所谓惰性,是指仅在它发觉鼠标有向它逼近时,它的位置才会突变。例如当预览框位于左上角(跨度占据0,1,2列),而鼠标从右侧首次进入第4列时, 它是不动的,但鼠标在第4列继续移动时,它才会突然移动到右侧。因此为了检测鼠标的这种行为,实际上在范例中我记录了鼠标最近两次的停留位置,即 lastSelection,currentSelection(二者的逻辑关系实际上是一个仅包含两个元素的队列)。
效果如下图所示:
这个范例在UI方面基本是采用对QQ2009的表情选择窗口的截图来制作的, 使用的表情文件夹是来自于qq2008的 “Face2” 。但该范例还是和真正的QQ有一些出入的地方,例如:
(1)QQ的表情选择窗口弹出来时,qq表情按钮是呈现按下状态的。范例为了简单期间,只是弹出模态对话框,所以这里不如QQ的 UI 自定义的那么彻底。
(2)QQ的表情选择窗口和其父窗口是非模态性的关系,而范例是模态关系,所以在没有加载任何图片的情况下,为了使窗口能够关闭,我做了一点特殊处理,也就是在范例中可以通过点击“空白处”的表情退出,而在QQ中点击空白位置是没有回应的。
(3)QQ的表情选择窗口有Tooltip,不过我不觉得这个功能很必要,估计很少会有人去关注这个功能,而且它还挡住了窗口的一部分。实现起来是很简单的,所以范例中没有tooltip了。
(4)QQ的表情选择窗口能自动调节自己的出现位置,尽可能靠近触发按钮,并且保证自身的可见性(完全位于屏幕范围以内)。操作中很多弹出式的窗口具有这种功能,例如 ToolTip , ComboBox, DateTimePicker 类控件的下拉窗口等。这个功能看起来简单,但是实现起来还是需要一定技巧和复杂度。范例中仅仅让窗口的位置固定出现在按钮上方。
(5)QQ的表情选择窗口对用户自己添加的表情在绘制时,使用了拉伸绘制。在范例中为了简单,没有考虑表情图片的大小。
本范例使用的代码都属于比较传统的技术,所以并没有什么特别需要单独列出和讲解的地方。由于最近该类实现的文章较多,所以将本文发于首页候选区。
在这里仅提供本范例的源代码下载连接:(可执行程序位于Debug目录中)
https://files.cnblogs.com/hoodlum1980/QQFaceVC.rar
--hoodlum1980
参考资料:
【1】 本文代码中,关于 GIF 图片的解码和展示引用了 CxImage 中的代码。关于 CxImage 的介绍地址:
http://www.codeproject.com/KB/graphics/cximage.aspx
【补充:】2013年12月 ,帮网友写的一个 DEMO (含源代码)。(采用 VC6.0 和 MFC 为基础开发)。
https://files.cnblogs.com/hoodlum1980/EmotionSelDemo.zip
说明:
-- hoodlum1980, ON 2013年12月12日。