#include "PicDateItem.h" #include #include #include #include #include "LogInfo.h" #include "ItemCommon.h" // 生成可能的最长时间字符串供尺寸计算使用(基于像素宽度) static QString generateMaxDateTimeString(const DateItemModel &model, const QFont &font) { if (model.datetimePattern.isEmpty()) return QString(); QString s = model.datetimePattern; QFontMetrics fm(font); auto longestFromList = [&fm] (const QStringList &lst, const QString &fallback) { int bestW = -1; QString best; for (const auto &v : lst) { int w = fm.horizontalAdvance(v); if (w > bestW) { bestW = w; best = v; } } return best.isEmpty() ? fallback : best; }; int i = s.indexOf("yyyy"); if (i != -1) { QString repl; if (!model.yearsMap.isEmpty()) { for (auto v : model.yearsMap.values()) if (v.length() > repl.length()) repl = v; } else { repl = QString::number(QDate::currentDate().year()); } s.replace(i, 4, repl); } i = s.indexOf("YY"); if (i != -1) { // 以像素宽度为准,'88' 通常足够宽 s.replace(i, 2, QString("88")); } i = s.indexOf("MM"); if (i != -1) { s.replace(i, 2, longestFromList(model.monthsMap, QString("88"))); } i = s.indexOf("dd"); if (i != -1) { s.replace(i, 2, longestFromList(model.daysMap, QString("88"))); } i = s.indexOf("HH"); if (i != -1) { s.replace(i, 2, longestFromList(model.hoursMap, QString("88"))); } QRegExp minutePattern("mm"); if (s.contains(minutePattern)) s.replace(minutePattern, QString("88")); QRegExp secondPattern("ss"); if (s.contains(secondPattern)) s.replace(secondPattern, QString("88")); i = s.indexOf("w"); if (i != -1) { s.replace(i, 1, longestFromList(model.weeksMap, QString("888"))); } QRegExp weekNumberPattern("c"); if (s.contains(weekNumberPattern)) s.replace(weekNumberPattern, QString("88")); return s; } PicDateItem::PicDateItem(QGraphicsItem *parent, QGraphicsScene *scene, const SourceType type) :PicTextItem(parent, scene, type) { m_timer.setInterval(20); connect(&m_timer, &QTimer::timeout, [this](){ updateDatetimeStr(); }); // m_timer.start(); } void PicDateItem::setModel(DateItemModel model) { m_model = std::move(model); // 计时:测量生成最长字符串和字体度量两段耗时 QElapsedTimer t1; t1.start(); m_maxDateTimeStr = generateMaxDateTimeString(m_model, font()); qint64 genUs = t1.nsecsElapsed() / 1000; // microseconds QElapsedTimer t2; t2.start(); if (m_maxDateTimeStr.isEmpty()) { m_maxSize = QSize(); } else { QFontMetrics fm(font()); int w = fm.horizontalAdvance(m_maxDateTimeStr); int h = fm.height(); m_maxSize = QSize(w, h); } qint64 fmUs = t2.nsecsElapsed() / 1000; // microseconds qDebug() << "PicDateItem::setModel timing(us): generate=" << genUs << ", fm=" << fmUs << ", total=" << (genUs + fmUs); m_currDateTimeStr = ItemUtils::generateTxtFromDateItemModel(m_model, QDateTime::currentDateTime()); applyModify(); } const DateItemModel& PicDateItem::model() const { return m_model; } bool PicDateItem::updateDatetimeStr() { if (m_model.datetimePattern.isEmpty()) return false; if(m_currDateTimeStr.isEmpty()) { m_currDateTimeStr = ItemUtils::generateTxtFromDateItemModel(m_model, QDateTime::currentDateTime()); applyModify(); return true; } auto now = QDateTime::currentDateTime(); auto str = ItemUtils::generateTxtFromDateItemModel(m_model, now); if(str == m_currDateTimeStr) { return false; } m_currDateTimeStr = str; applyModify(); return true; } void PicDateItem::setCustomAttrs(const QXmlStreamAttributes &attrs) { // 结构类似这样 // weeksMap = "MON
TUR
WED
TUE
THU
FRI
SAT
SUN" // yearsMap = "20232023年
20242024年
20252025年" auto m = DateItemModel(); DateItemModel::loadFromXml(m, attrs); setModel(std::move(m)); } void PicDateItem::saveCustomAttrs(QXmlStreamAttributes &attrs) { DateItemModel::saveToXml(m_model, attrs); } QImage PicDateItem::itemImage() { if(m_model.datetimePattern.isEmpty()) return QImage(); auto currImg = strToImage(m_currDateTimeStr); if (m_maxSize.isEmpty()) return currImg; int width = qMax(currImg.width(), m_maxSize.width()); int height = currImg.height(); QImage img(width, height, QImage::Format_ARGB32); img.fill(QColor(0,0,0,0).rgba()); QPainter painter(&img); int y = (height - currImg.height()) / 2; painter.drawImage(0, y, currImg); painter.end(); return img; } QRectF PicDateItem::boundingRect() const { return PicTextItem::boundingRect(); // // 优先使用已经应用变换后的 m_itemImage(与 PicTextItem 保持一致) // if (!m_itemImage.isNull()) { // return QRectF(0, 0, m_itemImage.width(), m_itemImage.height()); // } // // 否则基于缓存的最大像素尺寸和粗体倍数估算 // int w = m_maxSize.width(); // int h = m_maxSize.height(); // if (w <= 0 || h <= 0) // return QGraphicsTextItem::boundingRect(); // qreal bw = qreal(w) * qMax(1, m_boldMultiple); // return QRectF(0, 0, bw, qreal(h)); }