element.ui-Qt实现之时间控件
时分秒滚动控件
废话少说,直⼊主题,今天我们来实现⼀个时分秒滚动控件,类似前端组件
Qt实现的时间控件效果,因为不会传动态效果,所以没有滚动效果。
注意本⽂只介绍了时分秒滚动区域的实现,只是当前⽇期组件的⼀部分,整个⽇期控件在后⾯的博客中介绍
QScrollTime有三个listview组成,分别是可滚动的时、分、秒区域
QScrollTime::QScrollTime(QWidget *parent, Qt::WindowFlags enumFlags)
: QFrame(parent, enumFlags)
{
ui = new Ui::QScrollTime();
ui->setupUi(this);
ui->listViewHour->setModel(new QHourModel(this));
ui->listViewHour->setItemDelegate(new QScrollTimeDelegate(this));
ui->listViewHour->viewport()->installEventFilter(this);
ui->listViewHour->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->listViewMinute->setModel(new QMinuteModel(this));
ui->listViewMinute->setItemDelegate(new QScrollTimeDelegate(this));
ui->listViewMinute->viewport()->installEventFilter(this);
ui->listViewMinute->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->listViewSecond->setModel(new QSecondModel(this));
ui->listViewSecond->setItemDelegate(new QScrollTimeDelegate(this));
ui->listViewSecond->viewport()->installEventFilter(this);
ui->listViewSecond->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->frameScroll->setFixedHeight(ITEM_HEIGHT * 5.5);
setStyleSheet("\
#frameScroll,#listViewHour,#listViewMinute,#listViewSecond {background:transparent;} \
#frame {border-top:1px solid #D1D1D1;} \
#pBScrollCancel{border:none;} \
#pBScrollConfirm {border:none;color:#58BBE4;} \
#pBScrollConfirm:hover {color:#79C8E9;} \
#pBScrollConfirm:pressed {color:#4695B6;}");
connect(ui->listViewHour, &QListView::clicked, this, &QScrollTime::slotTimeClicked);
connect(ui->listViewMinute, &QListView::clicked, this, &QScrollTime::slotTimeClicked);
connect(ui->listViewSecond, &QListView::clicked, this, &QScrollTime::slotTimeClicked);
//垂直滚动条Value变化---当前时间被调整
connect(ui->listViewHour->verticalScrollBar(), &QScrollBar::valueChanged, this, &QScrollTime::slotTimeChangedByScorll);
connect(ui->listViewMinute->verticalScrollBar(), &QScrollBar::valueChanged, this, &QScrollTime::slotTimeChangedByScorll);
connect(ui->listViewSecond->verticalScrollBar(), &QScrollBar::valueChanged, this, &QScrollTime::slotTimeChangedByScorll);
connect(ui->pBScrollCancel, &QPushButton::clicked, this, [&](){
emit this->singalCancelClicked(m_origTime);
this->hide();
});
connect(ui->pBScrollConfirm, &QPushButton::clicked, this, [&](){
if (!m_origTime.isValid())
{
emit this->timeChanged(m_showTime);
}
this->hide();
});
setContentsMargins(LEFT_SHAWDE,TOP_SHAWDE,RIGHT_SHAWDE,BOTTOM_SHAWDE);
m_layerRect = QRect(contentsRect().left(), ITEM_HEIGHT * 2.5 + contentsRect().top(), contentsRect().width(), ITEM_HEIGHT);
setAttribute(Qt::WA_TranslucentBackground, true);
}
初始化时间
void QScrollTime::initTime(const QTime& time)
{
if (time.isValid())
{
m_origTime = time;
m_showTime = time;
QTimer::singleShot(0, this, SLOT(slotDelaySetTime())); //这⾥不能直接滚动,因为此刻还未显⽰,放到事件循环尾部
}
else
{element表格横向滚动条
m_showTime = QTime(0, 0, 0);
}
}
绘制时间区域底⾊和:号
绘制背景阴影
绘制区域底⾊
绘制:号
QPainter painter(this);
QPixmap pix(":/images/Calendar/timeBorder.png");
qDrawBorderPixmap(&painter, rect(), QMargins(0, 0, 0, 0), pix);
painter.fillRect(m_layerRect, QColor(88, 187, 228));
QRect colon1Rect(ui->listViewHour->width() + m_layerRect.left() - 2, ITEM_HEIGHT * 2.5 + contentsRect().top(), 4, ITEM_HEIGHT - 2);
QRect colon2Rect(ui->listViewSecond->x() + m_layerRect.left() - 2, ITEM_HEIGHT * 2.5 + contentsRect().top(), 4, ITEM_HEIGHT - 2);
QPen pen(Qt::white);
painter.setPen(pen);
painter.drawText(colon1Rect, Qt::AlignCenter, ":");
painter.drawText(colon2Rect, Qt::AlignCenter, ":");
过滤在当前时分秒区域⿏标事件
bool QScrollTime::eventFilter(QObject *obj, QEvent *event)
{
QEvent::Type t = event->type();
if ((obj == ui->listViewHour->viewport() || obj == ui->listViewMinute->viewport() || obj == ui->listViewSecond->viewport()) \
&& (t == QEvent::MouseMove || t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease || t == QEvent::MouseButtonDblClick)) {
QMouseEvent* pMouseEvent = dynamic_cast<QMouseEvent*>(event);
QPoint pos = pMouseEvent->pos();
if (ains(pos))
{
return true;
}
}
return false;
}
时分秒Item被点击后移到中间
void QScrollTime::slotTimeClicked(const QModelIndex &index)
{
if (QListView* view = qobject_cast<QListView*>(sender()))
{
setCenterCoveredRow(view, w());
}
}
当滚动条变化后,发射时间变化信号
这⾥有针对滚动超出范围后,微调整滚动条
void QScrollTime::slotTimeChangedByScorll()
{
bool bTimeChanged = false;
if (ui->listViewHour->verticalScrollBar() == sender())
{
const QModelIndex index = ui->listViewHour->indexAt(ui->listViewHour->viewport()->rect().center());
if (index.isValid())
{
//调整index位置
QRect indexRect = ui->listViewHour->visualRect(index);
indexRect.adjust(contentsRect().left(), contentsRect().top(), contentsRect().left(), contentsRect().top());  if (indexRect != m_layerRect.intersected(indexRect))
{
setCenterCoveredRow(ui->listViewHour, w());
return;
}
QString value = index.data(Qt::DisplayRole).toString();
if (!value.isEmpty())
{
int hour = Int();
if (hour != m_showTime.hour())
{
bTimeChanged = true;
m_showTime.setHMS(hour, m_showTime.minute(), m_showTime.second());
}
}
}
}
else if (ui->listViewMinute->verticalScrollBar() == sender())
{
const QModelIndex index = ui->listViewMinute->indexAt(ui->listViewMinute->viewport()->rect().center());  if (index.isValid())
{
//调整index位置
QRect indexRect = ui->listViewMinute->visualRect(index);
indexRect.adjust(contentsRect().left(), contentsRect().top(), contentsRect().left(), contentsRect().top());  if (indexRect != m_layerRect.intersected(indexRect))
{
setCenterCoveredRow(ui->listViewMinute, w());
return;
}
QString value = index.data(Qt::DisplayRole).toString();
if (!value.isEmpty())
{
int minu = Int();
if (minu != m_showTime.minute())
{
bTimeChanged = true;
m_showTime.setHMS(m_showTime.hour(), minu, m_showTime.second());
}
}
}
}
else if (ui->listViewSecond->verticalScrollBar() == sender())
{
const QModelIndex index = ui->listViewSecond->indexAt(ui->listViewSecond->viewport()->rect().center());  if (index.isValid())
{
//调整index位置
QRect indexRect = ui->listViewSecond->visualRect(index);
indexRect.adjust(contentsRect().left(), contentsRect().top(), contentsRect().left(), contentsRect().top());
indexRect.adjust(contentsRect().left(), contentsRect().top(), contentsRect().left(), contentsRect().top());  if (indexRect != m_layerRect.intersected(indexRect))
{
setCenterCoveredRow(ui->listViewSecond, w());
return;
}
QString value = index.data(Qt::DisplayRole).toString();
if (!value.isEmpty())
{
int secs = Int();
if (secs != m_showTime.second())
{
bTimeChanged = true;
m_showTime.setHMS(m_showTime.hour(), m_showTime.minute(), secs);
}
}
}
}
if (bTimeChanged)
{
emit timeChanged(m_showTime);
}
}
设置时分秒时,将滚动条值设置
void QScrollTime::slotDelaySetTime()
{
setCenterCoveredRow(ui->listViewHour, m_origTime.hour() + TOP_SPACEITEM_NUM);
setCenterCoveredRow(ui->listViewMinute, m_origTime.minute() + TOP_SPACEITEM_NUM);
setCenterCoveredRow(ui->listViewSecond, m_origTime.second() + TOP_SPACEITEM_NUM);
}
void QScrollTime::setCenterCoveredRow(QListView* view, int row)
{
if (view == ui->listViewHour)
{
ui->listViewHour->verticalScrollBar()->setValue((row - TOP_SPACEITEM_NUM) * ITEM_HEIGHT); }
else if (view == ui->listViewMinute)
{
ui->listViewMinute->verticalScrollBar()->setValue((row - TOP_SPACEITEM_NUM) * ITEM_HEIGHT); }
else if (view == ui->listViewSecond)
{
ui->listViewSecond->verticalScrollBar()->setValue((row - TOP_SPACEITEM_NUM) * ITEM_HEIGHT); }
}
时分秒的Model