七夕节基于Qt Android给女朋友做个转盘抽礼物的App

7 篇文章 2 订阅

前言

临近七夕,看到抖音上的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,具体安卓环境的搭建这里不介绍了

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

1.转盘

使用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

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值