当前位置:   article > 正文

七夕节基于Qt Android给女朋友做个转盘抽礼物的App_qt为女朋友写一个程序

qt为女朋友写一个程序

前言

临近七夕,看到抖音上的excel表格做的七夕抽奖,突发灵感,想着用代码也整一个出来。想着做个小程序效果最好,但自己没做过小程序,时间紧迫很悬;做个pc应用,那时最拿手的,很快,但要在电脑上打开才能看,局限性太大;最后决定做个安卓应用,用Qt就能做,装好后还能留存在手机中。

成品效果

抽奖原理

概率抽奖的本质其实就是生成随机数。

比如生成10以内的随机数,会生成0-9,每个数生成的概率是0.1,当0-9每个数都对应一个奖品,每个奖品的中奖概率是相同的,即0.1。

如果要每个奖品的概率不同,则我们可以选定区间对应一个奖品,比如 [0,2)对应一个奖品,那对应的概率就是0.3,[2,3)对应一个奖品,则概率是0.1,以此类推,如下图所示

抽奖代码实现

1.自定义表示区间的结构体

  1. struct RangValue {
  2. RangValue(qreal startVal, qreal endVal):
  3. m_startValue(startVal), m_endValue(endVal)
  4. {
  5. }
  6. bool contain(qreal val) {
  7. if(val >= m_startValue && val < m_endValue)
  8. return true;
  9. else
  10. return false;
  11. }
  12. qreal m_startValue;
  13. qreal m_endValue;
  14. };

2.给奖品设置概率分布,这里有12个奖品,可对照上面效果图,具体概率能够很清楚看出来,为了方便与界面交互,我这里放在一个map里

  1. m_optionMap.insert(0, RangValue(0, 0.05));
  2. m_optionMap.insert(1, RangValue(0.05, 0.08));
  3. m_optionMap.insert(2, RangValue(0.08, 0.13));
  4. m_optionMap.insert(3, RangValue(0.13, 0.135));
  5. m_optionMap.insert(4, RangValue(0.135, 0.235));
  6. m_optionMap.insert(5, RangValue(0.235, 0.335));
  7. m_optionMap.insert(6, RangValue(0.335, 0.535));
  8. m_optionMap.insert(7, RangValue(0.535, 0.835));
  9. m_optionMap.insert(8, RangValue(0.835, 0.885));
  10. m_optionMap.insert(9, RangValue(0.885, 0.89));
  11. m_optionMap.insert(10, RangValue(0.89, 0.94));
  12. m_optionMap.insert(11, RangValue(0.94, 1));

3.生成随机数,根据生成的随机数找出对应的产品

  1. int a = qrand()%m_srandBase;
  2. m_prizeIndex = getOption(a);
  1. int getOption(int rand)
  2. {
  3. int index = 0;
  4. qreal percentVal = (qreal)rand/(qreal)m_srandBase;
  5. QMapIterator<int, RangValue> iter(m_optionMap);
  6. while (iter.hasNext()) {
  7. iter.next();
  8. RangValue rangVal = iter.value();
  9. if(rangVal.contain(percentVal)) {
  10. index = iter.key();
  11. break;
  12. }
  13. }
  14. return index;
  15. }

其中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,具体安卓环境的搭建这里不介绍了

界面效果主要有三部分组成,转盘 + 中间点击(即开始抽奖部分)+ 抽奖结果 

1.转盘

使用paintEvent进行绘制

  1. void MainWindow::paintEvent(QPaintEvent *event)
  2. {
  3. QPainter painter(this);
  4. painter.setRenderHint(QPainter::Antialiasing);
  5. painter.setPen(Qt::NoPen);
  6. painter.setBrush(QColor(255, 211, 212));
  7. //画背景
  8. painter.drawRect(this->rect());
  9. //画标题栏
  10. painter.setBrush(QColor(255, 68, 72));
  11. painter.drawRect(QRect(0, 0, this->width(), this->height()/10));
  12. painter.setPen(Qt::white);
  13. m_font.setPixelSize(50);
  14. painter.setFont(m_font);
  15. painter.drawText(QRect(0, 0, this->width(), this->height()/10), Qt::AlignCenter, u8"七夕送女朋友的礼物");
  16. painter.setPen(Qt::NoPen);
  17. painter.setBrush(Qt::white);
  18. painter.drawRect(m_outFirstRect);
  19. painter.setBrush(QColor(255, 117, 88));
  20. painter.drawRect(m_outSecondRect);
  21. for(int i = 0; i < 4; ++i) {
  22. for(int j = 0; j < 4; ++j) {
  23. //排除中间四个
  24. if((i == 1 && (j == 1 || j == 2)) || (i == 2 && (j == 1 || j == 2)))
  25. continue;
  26. QRect sigleRect = QRect(m_startRect.x() + i*m_singleWidth,
  27. m_startRect.y() + j*m_singleWidth,
  28. m_startRect.width(), m_startRect.height());
  29. // qDebug() << __FUNCTION__ << sigleRect << startRect;
  30. painter.setBrush(m_colorMap.value(i + j*4));
  31. painter.drawRect(sigleRect);
  32. painter.setPen(QPen(Qt::white, 6*m_rScaleFactor));
  33. m_font.setPixelSize(40);
  34. painter.setFont(m_font);
  35. painter.drawText(sigleRect, Qt::AlignCenter, m_prizeMap.value(i + j*4));
  36. painter.setPen(Qt::NoPen);
  37. //画选中的边框
  38. if(m_indexList.at(m_index) == i + j*4) {
  39. painter.setBrush(Qt::NoBrush);
  40. painter.setPen(QPen(Qt::white, 16*m_rScaleFactor));
  41. painter.drawRect(sigleRect.adjusted(8*m_rScaleFactor, 8*m_rScaleFactor,
  42. -8*m_rScaleFactor, -8*m_rScaleFactor));
  43. painter.setPen(Qt::NoPen);
  44. }
  45. }
  46. }
  47. }

定时器控制绘制每个选项的边框

  1. m_pTimer = new QTimer(this);
  2. connect(m_pTimer, &QTimer::timeout, this, &MainWindow::onStartLottery);
  1. void MainWindow::onStartLottery()
  2. {
  3. m_index++;
  4. if(m_index >= 12) {
  5. m_index = 0;
  6. m_circle++;
  7. }
  8. //第二圈开始减速
  9. if(m_circle >= 2) {
  10. m_pTimer->start((m_circle)*120);
  11. //第5圈停
  12. if(m_circle >= 4 && m_index == m_prizeIndex)
  13. {
  14. update();
  15. m_pTimer->stop();
  16. //延时一下,不然show的时候会卡
  17. QTimer::singleShot(10, this, [=]{
  18. m_pMaskWidget->setPrizeText(m_prizeMap.value(m_indexList.at(m_index)));
  19. m_pMaskWidget->show();
  20. });
  21. m_pMiddleWidget->stop();
  22. }
  23. }
  24. update();
  25. }

2.开始抽奖点击

中间部分有一圈原点,抽奖的时候一直能红白闪动,为了与转盘的绘制不冲突,这个动画效果放在另外一个widget实现,如果放在一起绘制,两个定时器两个update会产生冲突

  1. void MiddleWidget::paintEvent(QPaintEvent *event)
  2. {
  3. QPainter painter(this);
  4. painter.setRenderHint(QPainter::Antialiasing);
  5. int middleStartX = 15*m_rScaleFactor;
  6. int middleStartY = 15*m_rScaleFactor;
  7. QRect middleStartRect(middleStartX, middleStartY, 15*m_rScaleFactor, 15*m_rScaleFactor);
  8. painter.setPen(Qt::NoPen);
  9. painter.setBrush(m_bMiddleFlag ? Qt::red : Qt::white);
  10. // painter.setBrush(Qt::white);
  11. int xCount = this->width()/23.*m_rScaleFactor;
  12. int yCount = this->height()/23.*m_rScaleFactor;
  13. for(int i = 0; i < xCount; ++i) {
  14. for(int j = 0; j < yCount; ++j) {
  15. if(i == 0 || i == (xCount - 1) || j == 0 || j == (yCount - 1)) {
  16. QRect ellipseRect = QRect(middleStartRect.x() + i*23*m_rScaleFactor, middleStartRect.y() + j*23*m_rScaleFactor,
  17. middleStartRect.width(), middleStartRect.height());
  18. painter.drawEllipse(ellipseRect);
  19. }
  20. }
  21. }
  22. m_font.setPixelSize(100);
  23. painter.setFont(m_font);
  24. painter.setPen(Qt::white);
  25. painter.drawText(this->rect(), Qt::AlignCenter, u8"开始\n抽奖");
  26. QWidget::paintEvent(event);
  27. }

也是定时器控制闪动的效果

  1. //定时器闪动
  2. m_pMiddleTimer = new QTimer(this);
  3. m_pMiddleTimer->setInterval(300);
  4. connect(m_pMiddleTimer, &QTimer::timeout, this, [=]{
  5. m_bMiddleFlag = !m_bMiddleFlag;
  6. update();
  7. });

3.抽奖结果

抽奖结果就是一个遮罩效果,在遮罩上画个爱心,毕竟七夕还是要有点浪漫的元素

画爱心:

  1. //绘制爱心的path
  2. m_heartPath.setFillRule(Qt::WindingFill);
  3. //调整爱心大小的系数
  4. double k = 18;
  5. float x = 16 * k * sin(0.0)*sin(0.0)*sin(0.0);
  6. float y = 13 * k * cos(0.0) - 5 * k*cos(0.0) - 2 * k*cos(0.0) - cos(0.0);
  7. m_heartPath.moveTo(x, -y);
  8. for (double t = 0.01; t < 100; t += 0.05)
  9. {
  10. x = 16 * k * sin(k*t)*sin(k*t)*sin(k*t);
  11. y = 13 * k * cos(k*t) - 5 * k * cos(2 * k * t) - 2 * k * cos(3 * k * t) - cos(4 * k * t);
  12. m_heartPath.lineTo(x, -y);
  13. }

在paintEvent绘制出来:

  1. void MaskWidget::paintEvent(QPaintEvent *event)
  2. {
  3. QPainter painter(this);
  4. painter.setRenderHint(QPainter::Antialiasing);
  5. painter.setBrush(QColor(0, 0, 0, 150));
  6. painter.setPen(Qt::NoPen);
  7. painter.drawRect(this->rect());
  8. painter.translate(this->width()/2, this->height()/2);
  9. // painter.setBrush(Qt::NoBrush);
  10. painter.setBrush(QColor(253, 189, 210));
  11. // painter.setPen(QColor(253, 189, 210));
  12. painter.drawPath(m_heartPath);
  13. painter.translate(-this->width()/2, -this->height()/2);
  14. painter.setPen(QColor(248, 10, 87));
  15. painter.setFont(m_font);
  16. painter.drawText(this->rect(), Qt::AlignCenter, "恭喜亲爱的抽中了\n" + m_prizeText);
  17. QWidget::paintEvent(event);
  18. }

结语

主体代码就这些,内容不多,把Qt For Android的环境搭起来就很好办了。里面的界面是按比例显示的,为了适配安卓的显示,如果在pc上运行是不适配的,只能在pc上运行看看效果。真正开发安卓的应用还是建议使用QML还做界面。

整个工程的代码在github, 地址为

https://github.com/a137748099/Turntable-lottery

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/194579
推荐阅读
相关标签
  

闽ICP备14008679号