临近七夕,看到抖音上的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;
            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();

2.开始抽奖点击

中间部分有一圈原点,抽奖的时候一直能红白闪动,为了与转盘的绘制不冲突,这个动画效果放在另外一个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();

3.抽奖结果

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

    //绘制爱心的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, 地址为

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

前言临近七夕,看到抖音上的excel表格做的七夕抽奖,突发灵感,想着用代码也整一个出来。想着做个小程序效果最好,但自己没做过小程序,时间紧迫很悬;做个pc应用,那时最拿手的,很快,但要在电脑上打开才能看,局限性太大;最后决定做个安卓应用,用Qt就能做,装好后还能留存在手机中。抽奖原理...
Qt框架之情人节玫瑰花案例项目 本项目是源自Qt框架书写的一个项目,Qt版本选择的是Qt 5.3.1 该版本bug较少,出错几率小,适合入门者学习, 源码我放在CSDN资源了和github主页了。 CSDN资源链接 https://download.csdn.net/download/A1521315qwss/15406494 github https://github.com/sunjunjunsun/MyLovers/tree/master 项目实现截图。 项目点击按钮后,整个屏幕都 玫瑰花会自动下
以上是朋友圈中一奇葩贴:“2月14情人节了,我决定造福大家。第2个赞和第14个赞的,我介绍你俩认识…………咱三吃饭…你俩请…”。现给出此贴下点赞的朋友名单,请你找出那两位要请客的倒霉蛋。 输入格式: 输入按照点赞的先后顺序给出不知道多少个点赞的人名,每个人名占一行,为不超过10个英文字母的非空单词,以回车结束。一个英文句点“.”标志输入的结束,这个符号不算在点赞名单里。
对于七夕节礼物,你可以考虑一些与Python相关的创意礼物,例如: 1. Python编程书籍:选择一本适合初学者或进阶者的Python编程书籍,帮助对方学习和提升编程技能。 2. Python编程教学课程:购买一份在线编程教学课程或订阅一个在线编程平台,让对方可以系统地学习Python编程。 3. 个性化Python编程笔记本:定制一个专属于对方的Python编程笔记本,可以在封面上印上对方的名字或一些有趣的Python图案。 4. Python编程工具包:准备一个Python编程工具包,包括一本参考书、一本练习册、一套Python编程工具和一张可爱的贺卡。 5. Python编程电子设备:如预算允许,可以考虑赠送一台新的笔记本电脑或平板电脑,用于进行Python编程和开发。 希望这些创意能给你带来一些灵感!
【报错】Qt报错 error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease” 青鸟青史: 解决了,找了半天,感谢大佬