Qt随机选人--年会抽奖小程序

一款基于Qt GUI的随机选人小程序。按动右边小把手,出现按下弹回动效,然后滚动,随机选人。

唯一的缺点:滚动不够平滑。

核心源码:

//random_selector.h

#ifndef RANDOM_SELCTION_H
#define RANDOM_SELCTION_H
#include <QWidget>
#include <QPainter>
#include <QTimer>
#include <QPropertyAnimation>

class CRandomSelector : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(double deviation READ deviation WRITE setDeviation NOTIFY sigDeviationChanged)

public:
    explicit CRandomSelector(QWidget* parent = Q_NULLPTR);
    virtual ~CRandomSelector();

    void setRange(int min, int max);

    inline int currentValue() const {return m_nCurrentValue; };
    void setCurrentValue(int value);

    inline double deviation() const { return m_nDeviation; }
    void setDeviation(double deviation);

    void startSelection();

protected:
    void paintEvent(QPaintEvent* event);
    void paintNum(QPainter& painter, int num, double deviation);

    // adjust select num to center
    void adjustCurrentValueToCenter();

signals:
    void sigValueChanged(int value);
    void sigDeviationChanged(double deviation);
    void sigFinishedSelection(int value);

private:
    int                 m_nMinValue             = 0;
    int                 m_nMaxValue             = 100;
    int                 m_nCurrentValue         = 0;

    double              m_nDeviation            = 0.0;
    int                 m_nNumSize              = 4; //偏移量
    const int           m_nInterval             = 1; //显示内容(数字)的间隔
    const int           m_nShowRowNum           = 3; //显示的行数

    QVector<QString>    m_vecUsers;

    QPropertyAnimation* m_pRollingAnimation     = Q_NULLPTR;
    QTimer*             m_pTimer                = Q_NULLPTR;
};

#endif // RANDOM_SELCTION_H
#include "random_selector.h"
#include <QMouseEvent>
#include <QDebug>
#include <QStringLiteral>

CRandomSelector::CRandomSelector(QWidget *parent) :
    QWidget(parent),
    m_nMinValue(0),
    m_nMaxValue(19),
    m_nCurrentValue(0),
    m_nDeviation(0.0),
    m_nNumSize(3),
    m_nInterval(1),
    m_nShowRowNum(3)
{
    for (int i = 0; i < 20; ++i) {
        m_vecUsers.append(QStringLiteral("张沫沫"));
        m_vecUsers.append(QStringLiteral("谢晓峰"));
        m_vecUsers.append(QStringLiteral("颜昊"));
        m_vecUsers.append(QStringLiteral("王瑶"));
        m_vecUsers.append(QStringLiteral("李文"));
    }

    m_pRollingAnimation = new QPropertyAnimation(this, "deviation");
    m_pRollingAnimation->setDuration(10);
    m_pRollingAnimation->setEasingCurve(QEasingCurve::OutQuad);
    connect(m_pRollingAnimation, &QPropertyAnimation::finished, [this]{
        m_nDeviation = -15;
        emit sigDeviationChanged((double)m_nDeviation / ((height() - 1) / m_nShowRowNum));

        adjustCurrentValueToCenter();
        m_pRollingAnimation->setDuration(m_pRollingAnimation->duration() + 15);
    });
}

CRandomSelector::~CRandomSelector()
{
    if (m_pTimer->isActive()) {
        m_pTimer->stop();

        m_pTimer->deleteLater();
        m_pTimer = Q_NULLPTR;
    }

    if (m_pRollingAnimation) {
        if (m_pRollingAnimation->state() != QPropertyAnimation::Stopped) {
            m_pRollingAnimation->stop();
            m_pRollingAnimation->deleteLater();
            m_pRollingAnimation = Q_NULLPTR;
        }
    }
}

void CRandomSelector::startSelection()
{
    // 3s
    if (m_pTimer == Q_NULLPTR) {
        m_pTimer = new QTimer(this);

        connect(m_pTimer, &QTimer::timeout, [this]{
            repaint();
            m_pRollingAnimation->stop();

            emit sigFinishedSelection(this->currentValue());
        });
    }
    m_pTimer->start(3000);

    m_pRollingAnimation->setDuration(50);

    m_nDeviation = -(this->height()) / m_nShowRowNum;
    adjustCurrentValueToCenter();
}

void CRandomSelector::setRange(int min, int max)
{
    m_nMinValue = min;
    m_nMaxValue = max;
    if (m_nCurrentValue < min)
    {
        m_nCurrentValue = min;
    }
    if (m_nCurrentValue > max)
    {
        m_nCurrentValue = max;
    }

    repaint();
}

void CRandomSelector::setCurrentValue(int value)
{
    if (m_nCurrentValue != value) {
        m_nCurrentValue = value;
    }
}

void CRandomSelector::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event)

    QPainter painter(this);
    painter.setRenderHint(QPainter::TextAntialiasing, true);

    QLinearGradient linearGradient(this->width(), 0, this->width(), this->height());
    linearGradient.setColorAt(0, QColor(0, 0, 0, 255));
    linearGradient.setColorAt(0.33, QColor(0, 0, 0, 69));
    linearGradient.setColorAt(0.666, QColor(0, 0, 0, 115));
    linearGradient.setColorAt(1.0, QColor(0, 0, 0, 255));

    QPainterPath path;
    path.addRoundedRect(this->rect(), 8, 8);
    painter.fillPath(path, QBrush(linearGradient));

    int Height = height() - 1;

    if ( m_nDeviation >= Height / m_nShowRowNum && m_nCurrentValue > m_nMinValue )
    {
        m_nDeviation -= Height / m_nShowRowNum;
        m_nCurrentValue -= m_nInterval;
    }

    if ( m_nDeviation <= -Height / m_nShowRowNum && m_nCurrentValue < m_nMaxValue )
    {
        m_nDeviation += Height / m_nShowRowNum;
        m_nCurrentValue += m_nInterval;
    }

    // draw middle number
    if (m_nCurrentValue > m_nMaxValue) {
        m_nCurrentValue = m_nMinValue;
    }
    if (m_nCurrentValue < m_nMinValue) {
        m_nCurrentValue = m_nMaxValue;
    }
    paintNum(painter, m_nCurrentValue, m_nDeviation);

    // draw top side num
    if (m_nCurrentValue != m_nMinValue)
    {
        int value = m_nCurrentValue - m_nInterval < m_nMinValue ? m_nMaxValue : m_nCurrentValue - m_nInterval;
        paintNum(painter, value, m_nDeviation - Height / m_nShowRowNum);
    } else {
        paintNum(painter, m_nMaxValue, m_nDeviation - Height / m_nShowRowNum);
    }

    // draw bottom side num
    if (m_nCurrentValue != m_nMaxValue)
    {
        int value = m_nCurrentValue + m_nInterval > m_nMaxValue? m_nMaxValue : m_nCurrentValue + m_nInterval;
        paintNum(painter, value, m_nDeviation + Height / m_nShowRowNum);
    } else {
         paintNum(painter, m_nMinValue, m_nDeviation + Height / m_nShowRowNum);
    }

    // draw two sides num
    for (int i = 2; i <= m_nShowRowNum / 2; ++i)
    {
        if (m_nCurrentValue - m_nInterval * i >= m_nMinValue)
        {
            if (m_nCurrentValue - - m_nInterval * i < m_nMinValue) {
                m_nCurrentValue = m_nMaxValue;
            } else {
                m_nCurrentValue -= m_nInterval*i;
            }
            paintNum(painter, m_nCurrentValue, m_nDeviation - Height / m_nShowRowNum * i);
        }

        if (m_nCurrentValue + m_nInterval * i <= m_nMaxValue)
        {
            if (m_nCurrentValue + m_nInterval * i > m_nMaxValue) {
                m_nCurrentValue = m_nMinValue;
            } else {
                m_nCurrentValue += m_nInterval*i;
            }
            paintNum(painter, m_nCurrentValue, m_nDeviation + Height / m_nShowRowNum * i);
        }
    }
}

/**
 * @brief draw num with diviation
 * @param num:      show num
 * @param deviation:divation to middle num
 */
void CRandomSelector::paintNum(QPainter &painter, int num, double deviation)
{
    int Width = width() - 1;
    int Height = height() - 1;
    int size = (Height - qAbs(deviation)) / m_nNumSize;
    int transparency = 255 - 255 * qAbs(deviation) * 0.9 / Height;
    int height = Height / m_nShowRowNum;
    int y = Height / 2 + deviation - height / 2;

    QFont font("SimHei");
    font.setPixelSize(size);
    painter.setFont(font);
    painter.setPen(QColor(255, 255, 255, transparency));

    if ( y >= 0 && y + height <= (Height + 20)) {
        painter.drawText(QRectF(0, y, Width, height), Qt::AlignCenter, m_vecUsers.at(num));
    }
}

void CRandomSelector::adjustCurrentValueToCenter()
{
    if ( m_nDeviation > height() / 10) {
        m_pRollingAnimation->setStartValue( ( height() - 1 ) / 8 - m_nDeviation);
        m_pRollingAnimation->setEndValue(0);
        m_nCurrentValue -= m_nInterval;
    } else if ( m_nDeviation > -height() / 10 ) {
        m_pRollingAnimation->setStartValue(m_nDeviation);
        m_pRollingAnimation->setEndValue(0);
    } else if ( m_nDeviation < -height() / 10 ) {
        m_pRollingAnimation->setStartValue(-(height() - 1) / 8 - m_nDeviation);
        m_pRollingAnimation->setEndValue(0);
        m_nCurrentValue += m_nInterval;
    }

    emit sigValueChanged(m_nCurrentValue);
    m_pRollingAnimation->start();
}

void CRandomSelector::setDeviation(double deviation)
{
    if (m_nDeviation != deviation) {
        m_nDeviation = deviation;
    }

    repaint();
}

猜你喜欢

转载自blog.csdn.net/u013015629/article/details/107947192