本系列预计实现
①刻度上方文字显示,
②时间轴拖动效果,
③时间轴刻度缩放,
④时间轴和其他控件联动显示,
⑤鼠标放置到时间轴,显示具体时间。
⑥通过定时器,实时更新时间轴
⑦时间轴上绘制时间片
完整代码可见GitHub - 754816/QT_TimeLine: qt时间轴实现效果
1、基础思路
主要是用到了之前章节中添加上的mouseMoveEvent和时间轴中心的当前时间m_MoveDateTime,然后新增了鼠标进入时间轴的事件函数(enterEvent),离开事件函数leaveEvent,以及一个用来展示时间文字的Label。
当鼠标进入时间轴时,根据鼠标位置,计算出相当于时间轴中心点的偏移量,根据偏移量换算出相对于时间轴中心的当前时间的偏移时间,调用SetHidden(false)显示label,当离开时隐藏label
2、代码实现
首先在初始化时,添加上label类,调整大小,重点是要设置跟踪鼠标轨迹,否则会影响mouseMoveEvent的调用频率。
void MyTimeLine::InitializeUI()
{
m_label = new QLabel(this);
m_label->setText(m_MoveDateTime.time().toString("hh:mm:ss"));
m_label->setHidden(true);
m_label->resize(60, 20);
//设置为true后,鼠标移动就会触发mouseMoveEvent,默认是false,不会自动跟踪
this->setMouseTracking(true);
}
然后添加进入和离开事件。
//============hpp===============
protected:
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
//=============cpp===============
void MyTimeLine::enterEvent(QEvent *)
{
m_label->setHidden(false);
}
void MyTimeLine::leaveEvent(QEvent *)
{
m_label->setHidden(true);
}
在mouseMoveEvent中添加上计算鼠标位移的代码,当鼠标移动后,计算一次。首先计算出鼠标相对于时间轴中心的偏移像素,用偏移像素除以每个块的长度,得到偏移比例,再用偏移比例乘以每个块对应的时间间隔,得到了偏移的秒数,然后用时间轴中心的时间加上偏移秒数,就得到了鼠标所指位置的偏移时间。
void MyTimeLine::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
int curMoveX = event->pos().x() - m_BeginX;
m_MoveX = m_totalX + curMoveX;
update();
}
//获取鼠标位置
QPoint mousePos = event->pos();
m_label->setHidden(false);
//调整到鼠标左边一点点的位置,方便完整展示
m_label->move(mousePos.x() + 3, this->size().height() - 15);
if(!m_bMoving)
{ //鼠标在拖动时间轴时,不更新label信息,只移动label
QString timestr = CalMouseTime(mousePos);
m_label->setText(timestr);
}
}
void MyTimeLine::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
m_bMoving = true;
m_BeginX = event->pos().x();
}
}
void MyTimeLine::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
m_bMoving = false;
m_totalX = m_totalX + event->pos().x() - m_BeginX;
m_MoveX = m_totalX;
}
}
QString MyTimeLine::CalMouseTime(QPoint p)
{
int width = this->size().width() / 2;
//计算鼠标位置相对于中心点的偏移量
double ratio = ((double)p.x() - (double)width) / (double)m_blockWidth;
//将偏移量转换为时间
QDateTime time = DateTimeUtil::sub(m_MoveDateTime, -1 * ratio * m_IntervalType);
return time.toString("hh:mm:ss");
}
3、在拖动时间轴的时候,只移动label,不修改label内容
在拖动时,鼠标显示的时间应该和时间轴同步,所以此时应该只移动label,不修改label内容
所以这里添加上一个全局变量m_bMoving,默认初始化为false,用来表示是否处于时间轴拖动状态,当鼠标在时间轴上按下时,m_bMoving设置为true,当结束拖动时,m_bMoving修改为false
void MyTimeLine::mousePressEvent(QMouseEvent *event)
{
m_bMoving = true;
...
}
void MyTimeLine::mouseMoveEvent(QMouseEvent *event)
{
//鼠标在拖动时间轴时,不更新label信息,只移动label
if(!m_bMoving)
{
...
}
}
void MyTimeLine::mouseReleaseEvent(QMouseEvent *event)
{
m_bMoving = false;
...
}
4、当鼠标滚轮缩放时,可以选择隐藏label
当鼠标滚轮缩放时,此时鼠标没有位移,所以也不会更新label,但是时间间隔已经变了,label上原来根据鼠标偏移位置算出来的偏移时间已不准确,需要重新计算,而通过放大和缩小按钮进行缩放的时候,鼠标必然是存在着移动,所以label始终是准确的。这里只给出解决思路,代码中未进行实现。
当鼠标缩放后,在鼠标滚轮事件中,添加上更新label的逻辑,由于鼠标滚轮事件wheelEvent(QWheelEvent *event)中,不方便直接获取鼠标位置,所以需要获取鼠标和时间轴的绝对坐标,也就是相对于屏幕左上角(0,0)点的坐标,然后就可以计算出鼠标相对于时间轴中心的偏移量,再根据比例计算出偏移的时间了。
当然,这里也可以选择直接隐藏label,用户在缩放完后,只要再触发下移动,就可以重新显示准确的时间。