独立博客:www.fearlazy.com
一、前言
有一次在查找android资料的时候无意间看到一个android上实现刮刮乐效果的文章,感觉这个有点意思,就想着用Qt来写写玩玩。本想借鉴一下大神的思路,只可惜文章太长实在没耐心看完它(个人比较喜欢简短一点的文章,所以长一点的文章都分成一二三四来写)。
二、思路
我们对刮刮乐的结构分析一下,会发现刮刮乐结构很简单,就只有两层。底层是结果展示的地方画好了就不用动了。顶层是涂层,鼠标拖动的时候需要擦除鼠标拖动的区域暴露出相应底层的内容。很显然难点就在于如何擦除顶层的内容。
刚开始我的思路是用一个路径(QPainterPath)来表示完整的顶层,另一个路径来保存鼠标拖动的经过的区域。用完整的路径减去经过的路径就是需要绘制的区域。后来仔细一想觉得这种方式如果顶层是用颜色来绘制可能可行(有兴趣的朋友可以试试)但是顶层需要用图片来表示就不好办了,于是果断放弃了。
我想大Qt不可能这么差吧,认真查询帮助文档看看有什么接口可用的,还真被我发现了QPainter::CompositionMode(定义数字图像合成模式的枚举类型)。其中有个值叫QPainter::CompositionMode_Clear,看到clear这个词就觉得有戏。测试了一下确实可行。方法就是在图像上先绘制一个你需要的背景图片,然后再绘制鼠标经过的路径。由于clear模式下后绘制的区域会清除之前该位置绘制的内容,这样就达到了擦除的目的了。
三、关键代码
1.成员变量:
QImage m_BottomImg; 用于保存底层绘制的内容
QImage m_TopImg; 用于保存顶层绘制的内容
QPainterPath m_movePath; 鼠标经过的区域
2.顶层的绘制:
void CGuaGuaLe::drawTop()
{
m_TopImg = QImage(size(),QImage::Format_ARGB32_Premultiplied);
QPainter painter(&m_TopImg);
painter.drawPixmap(rect(),QPixmap(":/ggl.jpg"));
painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.setBrush(Qt::yellow);
painter.drawPath(m_movePath);
}
image的大小设置与刮刮乐控件一样大,格式为ARGB,带有alpha通道的格式才能实现透明。我们先绘制顶层的背景图片,然后再绘制鼠标经过的区域即可。需要注意的是在绘制m_movePath前需要设置画刷,否则达不到擦除的效果。
3.鼠标经过路径的获取:
void CGuaGuaLe::mouseMoveEvent(QMouseEvent *event)
{
m_movePath.addEllipse(event->pos(),7,7);
update();
}
m_movePath的获取很简单,就是在move事件中添加圆(以鼠标的位置为中心,半径自己定)。
4.最后还需要注意一点就是要设置路径的填充规则模式为Qt::WindingFill:
m_movePath.setFillRule(Qt::WindingFill);
为什么要设置填充规则看一下图片立马就能明白了。
作者:fearlazy