#include "timeLineItem.h" #include namespace TimeLine { class TimeLineItemPrivate { public: TimeLineItemPrivate(); QRect m_rect; QRect m_titleRect; QColor m_lineColor; TimeUnit m_curTimeUnit; QDateTime m_curTime; QDateTime m_rightTime; //当前时间右边第一个需要输出展示的时间点 int m_curTimePos; //当前时间所在的位置(x值),默认在中间(=0) int m_rightTimePos; int m_scaleSize; //时间刻度大小,单位为像素 int m_scaleFactor; //缩放倍数 bool m_leftMouseIsDown; //鼠标左键是否按下 QPointF m_mouseDownPoint; //鼠标左键按下的坐标 QDateTime m_mouseDownTime; //鼠标左键是按下坐标对应的时间 DateTimeWidgetState m_curState; }; TimeLineItemPrivate::TimeLineItemPrivate() { m_lineColor = Qt::white; m_curTimeUnit = TU_Minute_1; m_curTime = QDateTime::currentDateTime();/*QDateTime::fromString("2024-12-10 20:15:00", "yyyy-MM-dd hh:mm:ss");*/ m_rightTime = m_curTime; m_curTimePos = 0; m_rightTimePos = 0; m_curState = realTime; m_scaleSize = 100; m_scaleFactor = (int)m_curTimeUnit; } TimeLineItem::TimeLineItem() : d_ptr(new TimeLine::TimeLineItemPrivate) { } TimeLineItem::~TimeLineItem() { delete d_ptr; } QRectF TimeLineItem::boundingRect() const { //return QRectF(-d_ptr->m_rect.width() / 2, -d_ptr->m_rect.height() / 2, d_ptr->m_rect.width(), d_ptr->m_rect.height()); return d_ptr->m_rect; } void TimeLineItem::updateBoundingRect(const QRect& r) { d_ptr->m_rect = QRect(-r.width() / 2, -r.height() / 2, r.width(), r.height()); d_ptr->m_titleRect = QRect(-r.width() / 2, -r.height() / 2, r.width(), 35); d_ptr->m_curTimePos = d_ptr->m_rect.right() - 80; } void TimeLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(widget); //QRect rect = boundingRect().toRect(); QPen pen = painter->pen(); QBrush brush = painter->brush(); QFont font = painter->font(); QString strCurState = ""; //绘制title,包含当前日期显示、状态显示,不同状态对应不同颜色 if(d_ptr->m_curState == realTime) { brush.setColor(QColor(39, 102, 59)); brush.setStyle(Qt::SolidPattern); strCurState = QString::fromWCharArray(L"实时数据"); } else { brush.setColor(QColor(46, 53, 63)); brush.setStyle(Qt::SolidPattern); strCurState = QString::fromWCharArray(L"历史数据"); } QRect titleRect = d_ptr->m_titleRect; painter->setBrush(brush); painter->drawRect(titleRect); //tiltle中的当前日期 pen.setColor(d_ptr->m_lineColor); font.setFamily(QString::fromWCharArray(L"微软雅黑")); font.setPointSize(10); font.setBold(true); painter->setPen(pen); painter->setFont(font); QFontMetrics metrics(font); QString strCurTime = d_ptr->m_curTime.toString("yyyy-MM-dd"); QRect textRect = metrics.boundingRect(strCurTime); painter->drawText(titleRect.x() + 10, titleRect.y() + (titleRect.height() - textRect.height()) * 0.5 + textRect.height() - 5, strCurTime); //tiltle中的当前状态 textRect = metrics.boundingRect(strCurState); painter->drawText(titleRect.x() + (titleRect.width() - textRect.width()) * 0.5, titleRect.y() + (titleRect.height() - textRect.height()) * 0.5 + textRect.height() - 5, strCurState); //刻度线 drawScaleLine(painter); //当前时间 painter->drawLine(d_ptr->m_curTimePos, d_ptr->m_titleRect.bottom() + 2, d_ptr->m_curTimePos, boundingRect().bottom()); } void TimeLineItem::drawScaleLine(QPainter* p) { QPen pen = p->pen(); pen.setWidth(2); p->setPen(pen); QRect rect = boundingRect().toRect(); d_ptr->m_rightTime = calculateRightTime(); d_ptr->m_rightTimePos = calculateRightTimePos(); int x_Right = d_ptr->m_rightTimePos; int x_Left = x_Right - d_ptr->m_scaleSize; while(1) { if(x_Right > rect.width() / 2 + d_ptr->m_scaleSize * 2) break; p->drawLine(x_Right, d_ptr->m_titleRect.bottom(), x_Right, d_ptr->m_titleRect.bottom() - 5); drawTimeText(p, x_Right); x_Right += d_ptr->m_scaleSize; } while(1) { if(x_Left < -rect.width() / 2 - d_ptr->m_scaleSize * 2) break; p->drawLine(x_Left, d_ptr->m_titleRect.bottom(), x_Left, d_ptr->m_titleRect.bottom() - 5); drawTimeText(p, x_Left); x_Left -= d_ptr->m_scaleSize; } } void TimeLineItem::drawTimeText(QPainter* p, int x) { QDateTime time = getTime(x); QString text = ""; QString text1 = ""; switch(d_ptr->m_curTimeUnit) { case TU_Year: { text = time.toString("yyyy"); break; } case TU_Month: { int month = time.date().month(); if (month == 1) text1 = time.toString("yyyy"); text = time.toString("MM"); break; } case TU_Day: { int day = time.date().day(); if (day == 1) text1 = time.toString("yyyy/MM"); text = time.toString("MM/dd"); break; } case TU_Hour: { int hour = time.time().hour(); if (hour == 0) text1 = time.toString("MM/dd"); text = time.toString("hh:mm"); break; } case TU_Minute_30: case TU_Minute_20: case TU_Minute_15: case TU_Minute_10: case TU_Minute_5: case TU_Minute_3: case TU_Minute_1: { int hour = time.time().hour(); if (hour == 0) text1 = time.toString("MM/dd"); text = time.toString("hh:mm"); break; } case TU_Second_30: case TU_Second_10: case TU_Second_1: { // int minute = time.time().minute(); // if(minute == 0) // text1 = time.toString("MM-dd hh:mm"); text = time.toString("hh:mm:ss"); break; } case TU_MSecond_500: case TU_MSecond_100: case TU_MSecond_50: case TU_MSecond_10: { // int minute = time.time().minute(); // if(minute == 0) // text1 = time.toString("MM-dd hh:mm"); text = time.toString("hh:mm:ss.zzz"); break; } default: break; } QFont font = p->font(); // font.setFamily(QString::fromWCharArray(L"微软雅黑")); // font.setPointSize(10); // font.setBold(true); // p->setFont(font); QFontMetrics metrics(font); if(!text.isEmpty()) { QRect textRect = metrics.boundingRect(text); p->drawText(x - textRect.width() * 0.5, d_ptr->m_titleRect.bottom() + textRect.height(), text); } if(!text1.isEmpty()) { QRect textRect = metrics.boundingRect(text1); p->drawText(x - textRect.width() * 0.5, d_ptr->m_titleRect.bottom() + textRect.height() * 2, text1); } } QDateTime TimeLineItem::calculateRightTime() { //必须保证时间点在整点时刻上,例如20mRange,时刻点为20:00、20:20、20:40、21:00,3mRange,时刻点为20:00,20:03、20:06...20:57、21:00。 //所以时间区间一定可以被所在但愿整除,比如不能出现7m的时间单元 QDateTime dateTime; QString strDateTime = d_ptr->m_curTime.toString("yyyyMMddhhmmsszzz");; switch(d_ptr->m_curTimeUnit) { case TU_Year: { strDateTime = d_ptr->m_curTime.addYears(1).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(4) + "0101000000000"; break; } case TU_Month: { strDateTime = d_ptr->m_curTime.addMonths(1).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(6) + "01000000000"; break; } case TU_Day: { strDateTime = d_ptr->m_curTime.addDays(1).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(8) + "000000000"; break; } case TU_Hour: { strDateTime = d_ptr->m_curTime.addSecs(60 * 60).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(10) + "0000000"; break; } case TU_Minute_30: { strDateTime = d_ptr->m_curTime.addSecs(30 * 60).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(10) + "0000000"; break; } case TU_Minute_20: { QString strBeginTime = strDateTime.left(10) + "0000000"; dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz"); while(1) { dateTime = dateTime.addSecs(20 * 60); if(dateTime >= d_ptr->m_curTime) return dateTime; } break; } case TU_Minute_15: { QString strBeginTime = strDateTime.left(10) + "0000000"; dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz"); while(1) { dateTime = dateTime.addSecs(15 * 60); if(dateTime >= d_ptr->m_curTime) return dateTime; } break; break; } case TU_Minute_10: { QString strBeginTime = strDateTime.left(10) + "0000000"; dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz"); while(1) { dateTime = dateTime.addSecs(10 * 60); if(dateTime >= d_ptr->m_curTime) return dateTime; } break; } case TU_Minute_5: { QString strBeginTime = strDateTime.left(10) + "0000000"; dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz"); while(1) { dateTime = dateTime.addSecs(5 * 60); if(dateTime >= d_ptr->m_curTime) return dateTime; } break; } case TU_Minute_3: { QString strBeginTime = strDateTime.left(10) + "0000000"; dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz"); while(1) { dateTime = dateTime.addSecs(3 * 60); if(dateTime >= d_ptr->m_curTime) return dateTime; } break; } case TU_Minute_1: { strDateTime = d_ptr->m_curTime.addSecs(1 * 60).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(12) + "00000"; break; } case TU_Second_30: { strDateTime = d_ptr->m_curTime.addSecs(30).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(12) + "00000"; break; } case TU_Second_10: { QString strBeginTime = strDateTime.left(12) + "00000"; dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz"); while(1) { dateTime = dateTime.addSecs(10); if(dateTime >= d_ptr->m_curTime) return dateTime; } break; } case TU_Second_1: { strDateTime = d_ptr->m_curTime.addSecs(1).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(14) + "000"; break; } case TU_MSecond_500: { strDateTime = d_ptr->m_curTime.addMSecs(500).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(14) + "000"; break; } case TU_MSecond_100: { strDateTime = d_ptr->m_curTime.addMSecs(100).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(15) + "00"; break; } case TU_MSecond_50: { strDateTime = d_ptr->m_curTime.addMSecs(50).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(15) + "00"; break; } case TU_MSecond_10: { strDateTime = d_ptr->m_curTime.addMSecs(10).toString("yyyyMMddhhmmsszzz"); strDateTime = strDateTime.left(16) + "0"; break; } default: break; } dateTime = QDateTime::fromString(strDateTime, "yyyyMMddhhmmsszzz"); return dateTime; } int TimeLineItem::calculateRightTimePos() { qint64 timeRange = d_ptr->m_rightTime.msecsTo(d_ptr->m_curTime); //右时刻晚于当前时刻,返回负值 timeRange = -timeRange; qint64 scaleRange = 0; switch(d_ptr->m_curTimeUnit) { case TU_Year: scaleRange = d_ptr->m_curTime.date().daysInYear() * 24 * 60 * 60 * (qint64)1000; break; case TU_Month: scaleRange = d_ptr->m_curTime.date().daysInMonth() * 24 * 60 * 60 * (qint64)1000; break; case TU_Day: scaleRange = 24 * 60 * 60 * 1000; break; case TU_Hour: scaleRange = 60 * 60 *1000; break; case TU_Minute_30: scaleRange = 30 * 60 *1000; break; case TU_Minute_20: scaleRange = 20 * 60 *1000; break; case TU_Minute_15: scaleRange = 15 * 60 *1000; break; case TU_Minute_10: scaleRange = 10 * 60 *1000; break; case TU_Minute_5: scaleRange = 5 * 60 *1000; break; case TU_Minute_3: scaleRange = 3 * 60 *1000; break; case TU_Minute_1: scaleRange = 60 * 1000; break; case TU_Second_30: scaleRange = 30 * 1000; break; case TU_Second_10: scaleRange = 10 * 1000; break; case TU_Second_1: scaleRange = 1 * 1000; break; case TU_MSecond_500: scaleRange = 500; break; case TU_MSecond_100: scaleRange = 100; break; case TU_MSecond_50: scaleRange = 50; break; case TU_MSecond_10: scaleRange = 10; break; default: break; } //qDebug() << timeRange << ", " << scaleRange; double dRatio = (double)timeRange / (double)scaleRange; //qDebug() << "leftTime:" << d_ptr->m_rightTime.toString("yyyy/MM/dd hh:mm:ss"); return d_ptr->m_curTimePos + (d_ptr->m_scaleSize * dRatio); } QDateTime TimeLineItem::calculateTime(double dUnit) { QDateTime dateTime; switch(d_ptr->m_curTimeUnit) { case TU_Year: { dateTime = d_ptr->m_rightTime.addYears((int)dUnit);//先计算年份 dateTime = dateTime.addMSecs(dateTime.date().daysInYear() * 24 * 60 * 60 * (qint64)1000 * (dUnit - (int)dUnit)); //再计算时间 break; } case TU_Month: { dateTime = d_ptr->m_rightTime.addMonths((int)dUnit);//先计算月份 dateTime = dateTime.addMSecs(dateTime.date().daysInMonth() * 24 * 60 * 60 * (qint64)1000 * (dUnit - (int)dUnit)); //再计算时间 break; } case TU_Day: dateTime = d_ptr->m_rightTime.addMSecs(24 * 60 * 60 * 1000 * dUnit); break; case TU_Hour: dateTime = d_ptr->m_rightTime.addMSecs(60 * 60 * 1000 * dUnit); break; case TU_Minute_30: dateTime = d_ptr->m_rightTime.addMSecs(30 * 60 * 1000 * dUnit); break; case TU_Minute_20: dateTime = d_ptr->m_rightTime.addMSecs(20 * 60 * 1000 * dUnit); break; case TU_Minute_15: dateTime = d_ptr->m_rightTime.addMSecs(15 * 60 * 1000 * dUnit); break; case TU_Minute_10: dateTime = d_ptr->m_rightTime.addMSecs(10 * 60 * 1000 * dUnit); break; case TU_Minute_5: dateTime = d_ptr->m_rightTime.addMSecs(5 * 60 * 1000 * dUnit); break; case TU_Minute_3: dateTime = d_ptr->m_rightTime.addMSecs(3 * 60 * 1000 * dUnit); break; case TU_Minute_1: dateTime = d_ptr->m_rightTime.addMSecs(60 * 1000 * dUnit); break; case TU_Second_30: dateTime = d_ptr->m_rightTime.addMSecs(30 * 1000 * dUnit); break; case TU_Second_10: dateTime = d_ptr->m_rightTime.addMSecs(10 * 1000 * dUnit); break; case TU_Second_1: dateTime = d_ptr->m_rightTime.addMSecs(1000 * dUnit); break; case TU_MSecond_500: dateTime = d_ptr->m_rightTime.addMSecs(500 * dUnit); break; case TU_MSecond_100: dateTime = d_ptr->m_rightTime.addMSecs(100 * dUnit); break; case TU_MSecond_50: dateTime = d_ptr->m_rightTime.addMSecs(50 * dUnit); break; case TU_MSecond_10: dateTime = d_ptr->m_rightTime.addMSecs(10 * dUnit); break; default: break; } return dateTime; } QDateTime TimeLineItem::getTime(int x) { double dUnit = (double)(x - d_ptr->m_rightTimePos) / (double)d_ptr->m_scaleSize; return calculateTime(dUnit); } qint64 TimeLineItem::getOffsetTimeValue(int x) { double dUnit = (double)(x) / (double)d_ptr->m_scaleSize; //在极小的时间刻度下做一定的倍数放大,从而让拖拽更平滑 switch(d_ptr->m_curTimeUnit) { case TU_MSecond_100: dUnit = dUnit * 2; break; case TU_MSecond_50: dUnit = dUnit * 5; break; case TU_MSecond_10: { if(dUnit < 0) dUnit = -0.1; else if(dUnit > 0) dUnit = 0.1; //dUnit = dUnit * 10; } break; default: break; } QDateTime dateTime = calculateTime(dUnit); //qDebug() << dUnit << " " << dateTime.toString("hh:mm:ss.zzz"); qint64 value = d_ptr->m_rightTime.msecsTo(dateTime); return value; } void TimeLineItem::setLineColor(QColor color) { d_ptr->m_lineColor = color; } void TimeLineItem::setScaleSize(int size) { d_ptr->m_scaleSize = size; } void TimeLineItem::setState(DateTimeWidgetState state) { d_ptr->m_curState = state; } void TimeLineItem::setTime(const QDateTime& time) { if(time > QDateTime::currentDateTime()) return; //qDebug() << "currTime:" << time.toString("hh:mm:ss.zzz"); d_ptr->m_curTime = time; prepareGeometryChange(); } QDateTime TimeLineItem::time() { return d_ptr->m_curTime; } void TimeLineItem::zoomIn() { d_ptr->m_scaleFactor++; if(d_ptr->m_scaleFactor > (int)TU_MSecond_10) d_ptr->m_scaleFactor = (int)TU_MSecond_10; d_ptr->m_curTimeUnit = (TimeUnit)d_ptr->m_scaleFactor; prepareGeometryChange(); //qDebug() << d_ptr->m_curTimeUnit; } void TimeLineItem::zoomOut() { d_ptr->m_scaleFactor--; if(d_ptr->m_scaleFactor < 1) d_ptr->m_scaleFactor = 1; d_ptr->m_curTimeUnit = (TimeUnit)d_ptr->m_scaleFactor; prepareGeometryChange(); //qDebug() << d_ptr->m_curTimeUnit; } void TimeLineItem::setTimeUnit(TimeUnit unit) { d_ptr->m_curTimeUnit = unit; } TimeUnit TimeLineItem::timeUnit() { return d_ptr->m_curTimeUnit; } } // namespace TimeLine