一款基于Qt GUI的随机选人小程序。按动右边小把手,出现按下弹回动效,然后滚动,随机选人。
唯一的缺点:滚动不够平滑。
核心源码:
//random_selector.h
#ifndef RANDOM_SELCTION_H
#define RANDOM_SELCTION_H
#include
#include
#include
#include
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 m_vecUsers;
QPropertyAnimation* m_pRollingAnimation = Q_NULLPTR;
QTimer* m_pTimer = Q_NULLPTR;
};
#endif // RANDOM_SELCTION_H
#include "random_selector.h"
#include
#include
#include
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();
}