本系列预计实现
①刻度上方文字显示,
②时间轴拖动效果,
③时间轴刻度缩放,
④时间轴和其他控件联动显示,
⑤鼠标放置到时间轴,显示具体时间。
⑥通过定时器,实时更新时间轴
⑦时间轴上绘制时间片
完整代码可见GitHub - 754816/QT_TimeLine: qt时间轴实现效果
1、基础思路
设置不同的时间间隔模式,然后通过按钮,或者鼠标滚轮事件来切换间隔模式,完成时间轴缩放
鼠标滚轮滑动后,时间间隔缩小,切换为了半个小时
2、将时间划分6个间隔模式
这里给出常用的1分/5分/10分/30分/1小时/2小时,共6个档次,后续也可以按照情况自定义添加
enum TimeInterval
{
_OneMin = 60, //间隔1分钟
_FiveMin = 300, //间隔5分钟
_TenMin = 600, //间隔10分钟
_ThirtyMin = 1800, //间隔30分钟
_OneHour = 3600, //间隔1小时
_TwoHour = 7200 //间隔2小时
};
定义时可以统一定义为秒,方便后续换算
3、缩放前后时间换算
在前两节中已经讲过了1小时间隔下,时间文字信息的计算,这里接着以1小时间隔切换到30分钟间隔为例,正中间红线的时间假设是12:34:56,原有的右边竖线的时间是12:00:00,切换后,应该是12:30:00,左边竖线的时间是13:00:00,切换后则依然是,12:34:56在12:30:00到13:00:00这个半小时间隔中。
切换后,那么带入到时间轴偏移中则是,时间轴相当于向左移动了4分56秒的距离
换算成比例则是(4*60+56)/ 1800,约0.164的块间隔
假设一个块的长度为m_blockWidth,那么时间轴上的竖线,则是整体相当于左移动0.164*m_blockWidth
4、计算时间文字信息
和前两节思路一样,先根据中间红线对应的时间,将其处理为整点时间,12:34:56出,计算出最左边竖线展示的时间,然后按照时间间隔依次增加计算,12:34:56对应的最左侧时间文字,是10:00:00,最右侧时间文字是15:30:00。
同理,拓展1分/5分/10分/30分时计算如下
QString MyTimeLine::CalText(const int index, const QDateTime midDateTime, const int moveRatio)
{
QTime time(0,0,0);
//STEP 1: 将时间按照间隔进行取模处理,例如间隔为1h,12:34:56处理后为12:00:00, 间隔30分钟,处理后12:30:00
QDateTime IntegerTime = midDateTime;
if(_OneHour == m_IntervalType)
{
IntegerTime.setTime(QTime(midDateTime.time().hour(), 0, 0));
}
if(_TwoHour == m_IntervalType)
{ //提醒:这里是做了按2舍去归整计算,不可以省略
int hh = midDateTime.time().hour() / 2 * 2;
IntegerTime.setTime(QTime(hh, 0, 0));
}
if(_OneMin == m_IntervalType)
{
IntegerTime.setTime(QTime(midDateTime.time().hour(), midDateTime.time().minute(), 0));
}
if(_FiveMin == m_IntervalType)
{
int mm = midDateTime.time().minute() / 5 * 5;
IntegerTime.setTime(QTime(midDateTime.time().hour(), mm, 0));
}
if(_TenMin == m_IntervalType)
{
int mm = midDateTime.time().minute() / 10 * 10;
IntegerTime.setTime(QTime(midDateTime.time().hour(), mm, 0));
}
if(_ThirtyMin == m_IntervalType)
{
int mm = midDateTime.time().minute() / 30 * 30;
IntegerTime.setTime(QTime(midDateTime.time().hour(), mm, 0));
}
//STEP 2: 根据中间的时间和Interval,计算出最左边的时间
QDateTime LeftTime = DateTimeUtil::sub(IntegerTime, (TimeLineStyle::TimeCount / 2) * m_IntervalType);
//STEP 3: 根据偏移量,更新最左边的时间
QDateTime MoveLeftTime = DateTimeUtil::sub(LeftTime, -1 * moveRatio * m_IntervalType);
//STEP 4: 根据index,计算i个间隔后的时间
time = DateTimeUtil::sub(MoveLeftTime, -1 * index * m_IntervalType).time();
return time.toString("hh:mm:ss");
}
5、添加按钮事件和鼠标滚轮事件
点击其他地方的放大按钮,实际是执行了一次设置时间间隔,然后在MyTimeLine内部中,调用update函数,重新绘制图像
//STEP 1:在类外添加上放大和缩小按钮的槽函数响应
connect(ui->pushButton_ZoomIn, &QPushButton::clicked, this, [=](){
ui->widget->SetTimeInterval(false);
});
connect(ui->pushButton_ZoomOut, &QPushButton::clicked, this, [=](){
ui->widget->SetTimeInterval(true);
});
//STEP 2:切换时间间隔,然后重新绘制
void MyTimeLine::SetTimeInterval(bool badd)
{
QList<TimeInterval> list = {_OneMin, _FiveMin, _TenMin, _ThirtyMin, _OneHour, _TwoHour};
int index = list.indexOf(m_IntervalType);
if(0 < index && index < list.size() - 1)
{
if(badd) index++;
else index--;
}
else if(0 == index && badd)
{ //放大坐标轴
index++;
}
else if(index == list.size() - 1 && !badd)
{ //缩小坐标轴
index--;
}
m_IntervalType = list.at(index);
SetDateTime(m_MoveDateTime);
//触发paintEvent进行绘制
update();
}
//STEP 3:添加上鼠标滚轮事件,滚动后调用设置间隔的函数
void MyTimeLine::wheelEvent(QWheelEvent *event)
{
if(event->delta() > 0)
{
SetTimeInterval(false);
}
else
{
SetTimeInterval(true);
}
m_label->setHidden(true);
}