赞
踩
临近七夕,看到抖音上的excel表格做的七夕抽奖,突发灵感,想着用代码也整一个出来。想着做个小程序效果最好,但自己没做过小程序,时间紧迫很悬;做个pc应用,那时最拿手的,很快,但要在电脑上打开才能看,局限性太大;最后决定做个安卓应用,用Qt就能做,装好后还能留存在手机中。
概率抽奖的本质其实就是生成随机数。
比如生成10以内的随机数,会生成0-9,每个数生成的概率是0.1,当0-9每个数都对应一个奖品,每个奖品的中奖概率是相同的,即0.1。
如果要每个奖品的概率不同,则我们可以选定区间对应一个奖品,比如 [0,2)对应一个奖品,那对应的概率就是0.3,[2,3)对应一个奖品,则概率是0.1,以此类推,如下图所示
1.自定义表示区间的结构体
- struct RangValue {
-
- RangValue(qreal startVal, qreal endVal):
- m_startValue(startVal), m_endValue(endVal)
- {
-
- }
-
- bool contain(qreal val) {
- if(val >= m_startValue && val < m_endValue)
- return true;
- else
- return false;
- }
- qreal m_startValue;
- qreal m_endValue;
- };
2.给奖品设置概率分布,这里有12个奖品,可对照上面效果图,具体概率能够很清楚看出来,为了方便与界面交互,我这里放在一个map里
- m_optionMap.insert(0, RangValue(0, 0.05));
- m_optionMap.insert(1, RangValue(0.05, 0.08));
- m_optionMap.insert(2, RangValue(0.08, 0.13));
- m_optionMap.insert(3, RangValue(0.13, 0.135));
- m_optionMap.insert(4, RangValue(0.135, 0.235));
- m_optionMap.insert(5, RangValue(0.235, 0.335));
- m_optionMap.insert(6, RangValue(0.335, 0.535));
- m_optionMap.insert(7, RangValue(0.535, 0.835));
- m_optionMap.insert(8, RangValue(0.835, 0.885));
- m_optionMap.insert(9, RangValue(0.885, 0.89));
- m_optionMap.insert(10, RangValue(0.89, 0.94));
- m_optionMap.insert(11, RangValue(0.94, 1));
3.生成随机数,根据生成的随机数找出对应的产品
- int a = qrand()%m_srandBase;
- m_prizeIndex = getOption(a);
- int getOption(int rand)
- {
- int index = 0;
- qreal percentVal = (qreal)rand/(qreal)m_srandBase;
- QMapIterator<int, RangValue> iter(m_optionMap);
- while (iter.hasNext()) {
- iter.next();
- RangValue rangVal = iter.value();
- if(rangVal.contain(percentVal)) {
- index = iter.key();
- break;
- }
- }
- return index;
- }
其中m_srandBase的值为1000,生成0-999的随机数,根据所在的区间就能找到对应的索引。
界面使用Qt进行实现,自己对QML不熟,为了快点做出来,选择使用QWidget。
Qt环境为Qt12.3 + armeabi-v7a,安卓配置jdk1.8.0_261 + SDK 26.1.1,+ NDK 19.2.5345600,具体安卓环境的搭建这里不介绍了
界面效果主要有三部分组成,转盘 + 中间点击(即开始抽奖部分)+ 抽奖结果
使用paintEvent进行绘制
- void MainWindow::paintEvent(QPaintEvent *event)
- {
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing);
- painter.setPen(Qt::NoPen);
- painter.setBrush(QColor(255, 211, 212));
- //画背景
- painter.drawRect(this->rect());
-
- //画标题栏
- painter.setBrush(QColor(255, 68, 72));
- painter.drawRect(QRect(0, 0, this->width(), this->height()/10));
- painter.setPen(Qt::white);
- m_font.setPixelSize(50);
- painter.setFont(m_font);
- painter.drawText(QRect(0, 0, this->width(), this->height()/10), Qt::AlignCenter, u8"七夕送女朋友的礼物");
- painter.setPen(Qt::NoPen);
-
- painter.setBrush(Qt::white);
- painter.drawRect(m_outFirstRect);
- painter.setBrush(QColor(255, 117, 88));
- painter.drawRect(m_outSecondRect);
- for(int i = 0; i < 4; ++i) {
- for(int j = 0; j < 4; ++j) {
- //排除中间四个
- if((i == 1 && (j == 1 || j == 2)) || (i == 2 && (j == 1 || j == 2)))
- continue;
- QRect sigleRect = QRect(m_startRect.x() + i*m_singleWidth,
- m_startRect.y() + j*m_singleWidth,
- m_startRect.width(), m_startRect.height());
- // qDebug() << __FUNCTION__ << sigleRect << startRect;
- painter.setBrush(m_colorMap.value(i + j*4));
- painter.drawRect(sigleRect);
- painter.setPen(QPen(Qt::white, 6*m_rScaleFactor));
- m_font.setPixelSize(40);
- painter.setFont(m_font);
- painter.drawText(sigleRect, Qt::AlignCenter, m_prizeMap.value(i + j*4));
- painter.setPen(Qt::NoPen);
- //画选中的边框
- if(m_indexList.at(m_index) == i + j*4) {
- painter.setBrush(Qt::NoBrush);
- painter.setPen(QPen(Qt::white, 16*m_rScaleFactor));
- painter.drawRect(sigleRect.adjusted(8*m_rScaleFactor, 8*m_rScaleFactor,
- -8*m_rScaleFactor, -8*m_rScaleFactor));
- painter.setPen(Qt::NoPen);
- }
-
- }
- }
- }
定时器控制绘制每个选项的边框
- m_pTimer = new QTimer(this);
- connect(m_pTimer, &QTimer::timeout, this, &MainWindow::onStartLottery);
- void MainWindow::onStartLottery()
- {
- m_index++;
- if(m_index >= 12) {
- m_index = 0;
- m_circle++;
- }
-
- //第二圈开始减速
- if(m_circle >= 2) {
- m_pTimer->start((m_circle)*120);
- //第5圈停
- if(m_circle >= 4 && m_index == m_prizeIndex)
- {
- update();
- m_pTimer->stop();
- //延时一下,不然show的时候会卡
- QTimer::singleShot(10, this, [=]{
- m_pMaskWidget->setPrizeText(m_prizeMap.value(m_indexList.at(m_index)));
- m_pMaskWidget->show();
- });
- m_pMiddleWidget->stop();
- }
- }
- update();
- }
中间部分有一圈原点,抽奖的时候一直能红白闪动,为了与转盘的绘制不冲突,这个动画效果放在另外一个widget实现,如果放在一起绘制,两个定时器两个update会产生冲突
- void MiddleWidget::paintEvent(QPaintEvent *event)
- {
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing);
- int middleStartX = 15*m_rScaleFactor;
- int middleStartY = 15*m_rScaleFactor;
- QRect middleStartRect(middleStartX, middleStartY, 15*m_rScaleFactor, 15*m_rScaleFactor);
- painter.setPen(Qt::NoPen);
- painter.setBrush(m_bMiddleFlag ? Qt::red : Qt::white);
- // painter.setBrush(Qt::white);
- int xCount = this->width()/23.*m_rScaleFactor;
- int yCount = this->height()/23.*m_rScaleFactor;
- for(int i = 0; i < xCount; ++i) {
- for(int j = 0; j < yCount; ++j) {
- if(i == 0 || i == (xCount - 1) || j == 0 || j == (yCount - 1)) {
- QRect ellipseRect = QRect(middleStartRect.x() + i*23*m_rScaleFactor, middleStartRect.y() + j*23*m_rScaleFactor,
- middleStartRect.width(), middleStartRect.height());
- painter.drawEllipse(ellipseRect);
- }
- }
- }
-
- m_font.setPixelSize(100);
- painter.setFont(m_font);
- painter.setPen(Qt::white);
- painter.drawText(this->rect(), Qt::AlignCenter, u8"开始\n抽奖");
-
- QWidget::paintEvent(event);
- }
也是定时器控制闪动的效果
- //定时器闪动
- m_pMiddleTimer = new QTimer(this);
- m_pMiddleTimer->setInterval(300);
- connect(m_pMiddleTimer, &QTimer::timeout, this, [=]{
- m_bMiddleFlag = !m_bMiddleFlag;
- update();
- });
抽奖结果就是一个遮罩效果,在遮罩上画个爱心,毕竟七夕还是要有点浪漫的元素
画爱心:
- //绘制爱心的path
- m_heartPath.setFillRule(Qt::WindingFill);
- //调整爱心大小的系数
- double k = 18;
- float x = 16 * k * sin(0.0)*sin(0.0)*sin(0.0);
- float y = 13 * k * cos(0.0) - 5 * k*cos(0.0) - 2 * k*cos(0.0) - cos(0.0);
- m_heartPath.moveTo(x, -y);
- for (double t = 0.01; t < 100; t += 0.05)
- {
- x = 16 * k * sin(k*t)*sin(k*t)*sin(k*t);
- y = 13 * k * cos(k*t) - 5 * k * cos(2 * k * t) - 2 * k * cos(3 * k * t) - cos(4 * k * t);
- m_heartPath.lineTo(x, -y);
- }
在paintEvent绘制出来:
- void MaskWidget::paintEvent(QPaintEvent *event)
- {
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing);
- painter.setBrush(QColor(0, 0, 0, 150));
- painter.setPen(Qt::NoPen);
- painter.drawRect(this->rect());
-
- painter.translate(this->width()/2, this->height()/2);
- // painter.setBrush(Qt::NoBrush);
- painter.setBrush(QColor(253, 189, 210));
- // painter.setPen(QColor(253, 189, 210));
- painter.drawPath(m_heartPath);
- painter.translate(-this->width()/2, -this->height()/2);
-
- painter.setPen(QColor(248, 10, 87));
- painter.setFont(m_font);
- painter.drawText(this->rect(), Qt::AlignCenter, "恭喜亲爱的抽中了\n" + m_prizeText);
- QWidget::paintEvent(event);
- }
主体代码就这些,内容不多,把Qt For Android的环境搭起来就很好办了。里面的界面是按比例显示的,为了适配安卓的显示,如果在pc上运行是不适配的,只能在pc上运行看看效果。真正开发安卓的应用还是建议使用QML还做界面。
整个工程的代码在github, 地址为
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。