效果图:
功能说明:该控件主要是通过鼠标左键点击后上下移动的同时,数字跟随滚动,鼠标松开时则选中中间的数字。(因不会录制动图,功能就简单文字说明了0.0)。
设计思路:设计该控件思路主要分三部分,第一是先标定两条临界线;第二时绘制4个数字显示的rect区域,图中只显示三个,还有一个则是绘制在显示区域外,根据鼠标是上划还是下划来确定初始的显示位置是在上方还是在下方;第三是重载鼠标事件,然后根据鼠标的移动来进行滚动绘制。
第一步和第二步主要代码逻辑如下:
void TimeSelectWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// 绘制背景
painter.save();
painter.setBrush(QColor(0, 0, 0, 100));
painter.drawRoundedRect(rect(), 5, 5);
painter.restore();
// 鼠标上划,Y轴值固定每次移动减2,然后在判读每一个处于最顶端(Y坐标为0)的矩形Y坐标是否小于
// 0,当小于零时处于最下方显示区域外的第4个矩形显示区域开始向上移动,以此形成循环滚动的视觉
// 效果
if(!m_curValueFlag)
{
if(m_firstY <= 0)
{
if(!m_pressFlag)
{
if(m_firstY <= -height() / 3 / 2)
{
m_firstY = height();
m_secendY = 0;
m_thridY = height() / 3;
m_fourY = height() / 3 * 2;
m_firstValue = m_fourValue + 1;
if(m_firstValue > m_maxValue)
{
m_firstValue = 0;
}
painterNum(&painter, m_secendY, m_thridY, m_fourY, m_firstY,
m_secendValue, m_thridValue, m_fourValue, m_firstValue);
}
else
{
m_firstY = 0;
m_secendY = height() / 3;
m_thridY = height() / 3 * 2;
m_fourY = height();
painterNum(&painter, m_firstY, m_secendY, m_thridY, m_fourY,
m_firstValue, m_secendValue, m_thridValue, m_fourValue);
}
}
else
{
painterNum(&painter, m_firstY, m_secendY, m_thridY, m_fourY,
m_firstValue, m_secendValue, m_thridValue, m_fourValue);
}
}
if(m_secendY <= 0)
{
if(!m_pressFlag)
{
if(m_secendY <= -height() / 3 / 2)
{
m_firstY = height() / 3 * 2;
m_secendY = height();
m_thridY = 0;
m_fourY = height() / 3;
m_secendValue = m_firstValue + 1;
if(m_secendValue > m_maxValue)
{
m_secendValue = 0;
}
painterNum(&painter, m_thridY, m_fourY, m_firstY, m_secendY,
m_thridValue, m_fourValue, m_firstValue, m_secendValue);
}
else
{
m_firstY = height();
m_secendY = 0;
m_thridY = height() / 3;
m_fourY = height() / 3 * 2;
painterNum(&painter, m_secendY, m_thridY, m_fourY, m_firstY,
m_secendValue, m_thridValue, m_fourValue, m_firstValue);
}
}
else
{
painterNum(&painter, m_secendY, m_thridY, m_fourY, m_firstY,
m_secendValue, m_thridValue, m_fourValue, m_firstValue);
}
}
if(m_thridY <= 0)
{
if(!m_pressFlag)
{
if(m_thridY <= -height() / 3 / 2)
{
m_firstY = height() / 3;
m_secendY = height() / 3 * 2;
m_thridY = height();
m_fourY = 0;
m_thridValue = m_secendValue + 1;
if(m_thridValue > m_maxValue)
{
m_thridValue = 0;
}
painterNum(&painter, m_fourY, m_firstY, m_secendY, m_thridY,
m_fourValue, m_firstValue, m_secendValue, m_thridValue);
}
else
{
m_firstY = height() / 3 * 2;
m_secendY = height();
m_thridY = 0;
m_fourY = height() / 3;
painterNum(&painter, m_thridY, m_fourY, m_firstY, m_secendY,
m_thridValue, m_fourValue, m_firstValue, m_secendValue);
}
}
else
{
painterNum(&painter, m_thridY, m_fourY, m_firstY, m_secendY,
m_thridValue, m_fourValue, m_firstValue, m_secendValue);
}
}
if(m_fourY <= 0)
{
if(!m_pressFlag)
{
if(m_fourY <= -height() / 3 / 2)
{
m_firstY = 0;
m_secendY = height() / 3;
m_thridY = height() / 3 * 2;
m_fourY = height();
m_fourValue = m_thridValue + 1;
if(m_fourValue > m_maxValue)
{
m_fourValue = 0;
}
painterNum(&painter, m_firstY, m_secendY, m_thridY, m_fourY,
m_firstValue, m_secendValue, m_thridValue, m_fourValue);
}
else
{
m_firstY = height() / 3;
m_secendY = height() / 3 * 2;
m_thridY = height();
m_fourY = 0;
painterNum(&painter, m_fourY, m_firstY, m_secendY, m_thridY,
m_fourValue, m_firstValue, m_secendValue, m_thridValue);
}
}
else
{
painterNum(&painter, m_fourY, m_firstY, m_secendY, m_thridY,
m_fourValue, m_firstValue, m_secendValue, m_thridValue);
}
}
}
// 鼠标下划,Y轴值固定每次移动加2,然后在判读每一个处于显示区域外(Y坐标为0)的矩形Y坐标是否
// 小于0,当小于零时处于最上方显示区域外的第4个矩形显示区域开始向下移动,以此形成循环滚动的视
// 觉效果
else
{
if(m_fourY <= 0)
{
if(!m_pressFlag)
{
if(m_fourY >= -height() / 3 / 2)
{
m_firstY = height() / 3;
m_secendY = height() / 3 * 2;
m_thridY = -height() / 3;
m_fourY = 0;
m_thridValue = m_fourValue - 1;
if(m_thridValue < 0)
{
m_thridValue = m_maxValue;
}
painterNum(&painter, m_fourY, m_firstY, m_secendY, m_thridY,
m_fourValue, m_firstValue, m_secendValue, m_thridValue);
}
else
{
m_firstY = 0;
m_secendY = height() / 3;
m_thridY = height() / 3 * 2;
m_fourY = -height() / 3;
painterNum(&painter, m_firstY, m_secendY, m_thridY, m_fourY,
m_firstValue, m_secendValue, m_thridValue, m_fourValue);
}
}
else
{
painterNum(&painter, m_firstY, m_secendY, m_thridY, m_fourY,
m_firstValue, m_secendValue, m_thridValue, m_fourValue);
}
}
if(m_thridY <= 0)
{
if(!m_pressFlag)
{
if(m_thridY >= -height() / 3 / 2)
{
m_firstY = height() / 3 * 2;
m_secendY = -height() / 3;
m_thridY = 0;
m_fourY = height() / 3;
m_secendValue = m_thridValue - 1;
if(m_secendValue < 0)
{
m_secendValue = m_maxValue;
}
painterNum(&painter, m_thridY, m_fourY, m_firstY, m_secendY,
m_thridValue, m_fourValue, m_firstValue, m_secendValue);
}
else
{
m_firstY = height() / 3;
m_secendY = height() / 3 * 2;
m_thridY = -height() / 3;
m_fourY = 0;
if(m_thridValue < 0)
{
m_thridValue = m_maxValue;
}
painterNum(&painter, m_fourY, m_firstY, m_secendY, m_thridY,
m_fourValue, m_firstValue, m_secendValue, m_thridValue);
}
}
else
{
painterNum(&painter, m_fourY, m_firstY, m_secendY, m_thridY,
m_fourValue, m_firstValue, m_secendValue, m_thridValue);
}
}
if(m_secendY <= 0)
{
if(!m_pressFlag)
{
if(m_secendY >= -height() / 3 / 2)
{
m_firstY = -height() / 3;
m_secendY = 0;
m_thridY = height() / 3;
m_fourY = height() / 3 * 2;
m_firstValue = m_secendValue - 1;
if(m_firstValue < 0)
{
m_firstValue = m_maxValue;
}
painterNum(&painter, m_secendY, m_thridY, m_fourY, m_firstY,
m_secendValue, m_thridValue, m_fourValue, m_firstValue);
}
else
{
m_firstY = height() / 3 * 2;
m_secendY = -height() / 3;
m_thridY = 0;
m_fourY = height() / 3;
painterNum(&painter, m_thridY, m_fourY, m_firstY, m_secendY,
m_thridValue, m_fourValue, m_firstValue, m_secendValue);
}
}
else
{
painterNum(&painter, m_thridY, m_fourY, m_firstY, m_secendY,
m_thridValue, m_fourValue, m_firstValue, m_secendValue);
}
}
if(m_firstY <= 0)
{
if(!m_pressFlag)
{
if(m_firstY >= -height() / 3 / 2)
{
m_firstY = 0;
m_secendY = height() / 3;
m_thridY = height() / 3 * 2;
m_fourY = -height() / 3;
m_fourValue = m_firstValue - 1;
if(m_fourValue < 0)
{
m_fourValue = m_maxValue;
}
painterNum(&painter, m_firstY, m_secendY, m_thridY, m_fourY,
m_firstValue, m_secendValue, m_thridValue, m_fourValue);
}
else
{
m_firstY = -height() / 3;
m_secendY = 0;
m_thridY = height() / 3;
m_fourY = height() / 3 * 2;
painterNum(&painter, m_secendY, m_thridY, m_fourY, m_firstY,
m_secendValue, m_thridValue, m_fourValue, m_firstValue);
}
}
else
{
painterNum(&painter, m_secendY, m_thridY, m_fourY, m_firstY,
m_secendValue, m_thridValue, m_fourValue, m_firstValue);
}
}
}
// 绘制临界线
painter.save();
QPen pen(Qt::blue);
pen.setWidth(2);
painter.setPen(pen);
painter.drawLine(0, height() / 3, width(), height() / 3);
painter.drawLine(0, height() / 3 * 2, width(), height() / 3 * 2);
painter.restore();
}
// 绘制数字显示区域,同时循环滚动绘制数字
void TimeSelectWidget::painterNum(QPainter *pPainter, int y1, int y2, int y3, int y4, int value1, int value2, int value3, int value4)
{
pPainter->save();
QPen txetPen(Qt::white);
txetPen.setWidth(2);
pPainter->setPen(txetPen);
QFont font = pPainter->font();
font.setBold(true);
font.setPixelSize(18);
pPainter->setFont(font);
QRect rect(0, y1, width(), height() / 3);
pPainter->drawText(rect, Qt::AlignCenter, QString::number(value1));
font.setPixelSize(24);
pPainter->setFont(font);
rect = QRect(0, y2, width(), height() / 3);
pPainter->drawText(rect, Qt::AlignCenter, QString::number(value2));
font.setPixelSize(18);
pPainter->setFont(font);
rect = QRect(0, y3, width(), height() / 3);
pPainter->drawText(rect, Qt::AlignCenter, QString::number(value3));
font.setPixelSize(18);
pPainter->setFont(font);
rect = QRect(0, y4, width(), height() / 3);
pPainter->drawText(rect, Qt::AlignCenter, QString::number(value4));
pPainter->restore();
m_selectValue = value2;
}
第三步重载鼠标事件:
// 获取鼠标按下的开始位置
void TimeSelectWidget::mousePressEvent(QMouseEvent *event)
{
m_startPos = event->pos();
m_pressFlag = true;
}
void TimeSelectWidget::mouseMoveEvent(QMouseEvent *event)
{
// 鼠标按下才开始进行移动(暂时没有限定鼠标按键)
if(m_pressFlag)
{
// 小于0则说明鼠标是上划,大于0则是下划,然后根据鼠标移动后Y坐标的临界值去改变rect区域
// 显示的数字
if(event->pos().y() - m_startPos.y() < 0)
{
if(m_firstY == -height() / 3)
{
m_firstY = height();
m_firstValue = m_fourValue + 1;
if(m_firstValue > m_maxValue)
{
m_firstValue = 0;
}
}
if(m_secendY == -height() / 3)
{
m_secendY = height();
m_secendValue = m_firstValue + 1;
if(m_secendValue > m_maxValue)
{
m_secendValue = 0;
}
}
if(m_thridY == -height() / 3)
{
m_thridY = height();
m_thridValue = m_secendValue + 1;
if(m_thridValue > m_maxValue)
{
m_thridValue = 0;
}
}
if(m_fourY == -height() / 3)
{
m_fourY = height();
m_fourValue = m_thridValue + 1;
if(m_fourValue > m_maxValue)
{
m_fourValue = 0;
}
}
m_firstY -= m_moveValue;
m_secendY -= m_moveValue;
m_thridY -= m_moveValue;
m_fourY -= m_moveValue;
m_curValueFlag = false;
}
else
{
if(m_firstY == 0)
{
m_fourY = -height() / 3;
m_fourValue = m_firstValue - 1;
if(m_fourValue < 0)
{
m_fourValue = m_maxValue;
}
}
if(m_fourY == 0)
{
m_thridY = -height() / 3;
m_thridValue = m_fourValue - 1;
if(m_thridValue < 0)
{
m_thridValue = m_maxValue;
}
}
if(m_thridY == 0)
{
m_secendY = -height() / 3;
m_secendValue = m_thridValue - 1;
if(m_secendValue < 0)
{
m_secendValue = m_maxValue;
}
}
if(m_secendY == 0)
{
m_firstY = -height() / 3;
m_firstValue = m_secendValue - 1;
if(m_firstValue < 0)
{
m_firstValue = m_maxValue;
}
}
m_firstY += m_moveValue;
m_secendY += m_moveValue;
m_thridY += m_moveValue;
m_fourY += m_moveValue;
m_curValueFlag = true;
}
update();
}
}
void TimeSelectWidget::mouseReleaseEvent(QMouseEvent *event)
{
m_pressFlag = false;
update();
}
功能较为简单就不做过多的文字说明了。