123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- //qcustomcalendarwidget.cpp
- #include "calendarwidgetex.h"
- #include <QPainter>
- #include <QProxyStyle>
- #include <QTableView>
- #include <QHeaderView>
- #include <QLayout>
- #include <QPushButton>
- #include <QLabel>
- #include <QDebug>
- #include <QLayoutItem>
- #include <QKeyEvent>
- #include <QPainterPath>
- #include "scopeselectionmodel.h"
- #include "PaintHelper/painthelper.h"
- // #include "StyleManager/lhstylemanager.h"
- //#include "utility/utility.h"
- #include "UIStyleManager.h"
- CalendarWidgetEx::CalendarWidgetEx(QWidget *parent)
- : QCalendarWidget(parent)
- , m_modeSelection(Normal)
- , m_pDateScopeModel(nullptr)
- , m_nLineHeight(-1)
- , m_hasTopSplitLine(false)
- {
- setWindowFlag(Qt::NoDropShadowWindowHint);
- setAttribute(Qt::WA_TranslucentBackground);
- setWindowFlag(Qt::FramelessWindowHint);
- //使用固定尺寸(无法通过resize控制日历大小, 日历整体大小由layout下的控件的fixSize决定)
- //layout()->setSizeConstraint(QLayout::SetFixedSize);
- //禁用原有的年月导航
- setNavigationBarVisible(false);
- //禁用横向纵向表头
- setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
- setHorizontalHeaderFormat(QCalendarWidget::NoHorizontalHeader);
- //取消聚焦虚线框
- setStyle(new NoFocusStyle(this));
- QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
- if(vBodyLayout == nullptr) return;
- m_pNav = new CalendarNav(this);
- m_pHeader = new CalendarHeader(this);
- setFirstDayOfWeek(Qt::Sunday);
- m_pHeader->SetFirstDayOfWeek(Qt::Sunday);
- vBodyLayout->insertWidget(0, m_pNav);
- // 导航和星期标题间距
- vBodyLayout->insertSpacing(1, 10);
- vBodyLayout->insertWidget(2, m_pHeader);
- vBodyLayout->setSpacing(10);
- vBodyLayout->setContentsMargins(10,0,10,10);
- m_nLineHeight = vBodyLayout->itemAt(4)->widget()->mapTo(this, QPoint(0,0)).y();
- //qDebug()<<"m_nLineHeight"<<m_nLineHeight<<vBodyLayout->itemAt(3)->widget()->height();
- //开启鼠标监测
- QTableView *pCalendarView = dynamic_cast<QTableView*>(vBodyLayout->itemAt(4)->widget());
- if (Q_NULLPTR != pCalendarView) {
- pCalendarView->setMouseTracking(true);
- }
- //在构造函数里取消selectionChanged, clicked事件没用, 因为执行QDateTimeEdit的setCalendarWidget方法时, 会重新绑定
- //所以必须等setCalendarWidget执行完后再取消事件
- //calendarWidget->disconnect(calendarWidget, &QCalendarWidget::selectionChanged, 0, 0);
- //calendarWidget->disconnect(calendarWidget, &QCalendarWidget::clicked, 0, 0);
- setMouseTracking(true);
- // 设置默认字体后,修复单元格变得很宽的问题
- for (QWidget* f : findChildren<QWidget*>()) {
- if(f->objectName() != "qt_calendar_calendarview") continue;
- QTableView* pView = reinterpret_cast<QTableView*>(f);
- if (nullptr != pView && nullptr != pView->horizontalHeader()) {
- pView->horizontalHeader()->setMaximumSectionSize(WINDOW_WIDTH / 8);
- }
- }
- connect(this, &QCalendarWidget::clicked, this, &CalendarWidgetEx::OnClicked);
- // initSkinColor();
- setUIStyle();
- /* 设置对象名称,加载QSS */
- // this->setObjectName("calendarWidget");
- this->setStyleSheet("background-color:transparent;");
- }
- void CalendarWidgetEx::SetSelectMode(SelectMode mode, ScopeSelectionModel *pDataModel)
- {
- m_listMultiSelectDays.clear();
- m_modeSelection = mode;
- if(m_pDateScopeModel == nullptr)
- {
- m_pDateScopeModel = pDataModel;
- connect(m_pDateScopeModel, &ScopeSelectionModel::sig_Update, this, static_cast<void(QWidget::*)()>(&QWidget::update));
- }
- update();
- }
- void CalendarWidgetEx::hideNavigatioinButton(bool bPreYear, bool bPreMon, bool bNextYear, bool bNextMon)
- {
- QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
- if(vBodyLayout == nullptr) return;
- CalendarNav *pNav = qobject_cast<CalendarNav*>(vBodyLayout->itemAt(0)->widget());
- if (nullptr != pNav) {
- pNav->hideNextMonth(bNextMon);
- pNav->hideNextYear(bNextYear);
- pNav->hidePreMonth(bPreMon);
- pNav->hidePreYear(bPreYear);
- }
- }
- /* 设置UI样式,0亮色,1暗色 */
- void CalendarWidgetEx::setUIStyle()
- {
- if(EPUIStyle.getUIStyle() == enum_UIStyle::UI_Light)
- {
- m_style = 0;
- }
- else if(EPUIStyle.getUIStyle() == enum_UIStyle::UI_Dark)
- {
- m_style = 1;
- }
- initSkinColor();
- m_pNav->setQSS(m_style);
- m_pHeader->setQSS(m_style);
- update();
- }
- void CalendarWidgetEx::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
- {
- PainterEx *painterEx = static_cast<PainterEx*>(painter);
- painterEx->setRenderHint(QPainter::Antialiasing);
- QColor textColor;
- {//正常
- textColor = m_normalTextColor;
- }
- #if 0
- // 周六,周日特殊颜色
- int nWeek = date.dayOfWeek();
- if (6 == nWeek || 7 == nWeek) {
- textColor = QColor(255,149,0);
- }
- #endif
- //鼠标移入
- if(date == m_dateMouseOver)
- {
- QPoint center = rect.center();
- QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
- painterEx->DrawRoundedRect(rc, 2.0, m_hoverBlockColor);
- textColor = m_normalTextColor;
- }
- //当天
- if(date == QDate::currentDate())
- {
- painter->save();
- QPoint center = rect.center();
- QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
- painter->setPen(m_todayTextColor);
- painter->setBrush(Qt::transparent);
- painter->drawRoundedRect(rc, 2.0, 2.0);
- textColor = m_todayTextColor;
- painter->restore();
- }
- //选中
- if(m_modeSelection == Multi && m_listMultiSelectDays.contains(date))
- {
- //painterEx->DrawCircle(QRectF(rect).center(), 9, QColor(9,109,217));
- QPoint center = rect.center();
- QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
- painterEx->DrawRoundedRect(rc, 2.0, m_selectBlockColor);
- textColor = m_selectTextColor;
- }
- if(m_modeSelection == Normal && date == selectedDate())
- {
- //painterEx->DrawCircle(QRectF(rect).center(), 9, QColor(9, 109, 217));
- QPoint center = rect.center();
- QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
- painterEx->DrawRoundedRect(rc, 2.0, m_selectBlockColor);
- textColor = m_selectTextColor;
- }
- if(m_modeSelection == Scope && m_pDateScopeModel != nullptr && m_pDateScopeModel->dtFirst.isValid() && m_pDateScopeModel->dtSecond.isValid())
- {
- QDate scopeStart = qMin(m_pDateScopeModel->dtFirst, m_pDateScopeModel->dtSecond);
- QDate scopeEnd = qMax(m_pDateScopeModel->dtFirst, m_pDateScopeModel->dtSecond);
- if(date == qBound(scopeStart, date, scopeEnd) && date.month() == monthShown())
- {
- painterEx->SetBrushOnly(m_hoverBlockColor);
- if(date == scopeStart || date == scopeEnd)
- {
- textColor = m_selectTextColor;
- QPoint center = rect.center();
- QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
- painterEx->DrawRoundedRect(rc, 2.0, m_selectBlockColor);
- }
- else
- {
- QRect r(0, 0, rect.width(), TEXT_WIDTH);
- r.moveCenter(rect.center());
- painterEx->drawRect(r);
- }
- }
- }
- //不可选的日期或非当月日期
- if(date < minimumDate() || date > maximumDate() || date.month() != monthShown())
- {
- textColor = m_disableTextColor;
- }
- //当天且未选中, 加粗
- bool isBold = (date == QDate::currentDate() && date != selectedDate());
- QString strDay(QString("%1").arg(date.day(), 2, 10, QLatin1Char('0')));
- painterEx->setFont(FontEx(font().family(), DEFAULT_FONT_SIZE, isBold));
- QRect rc = rect.adjusted(-1, 0, 0, -3); // 矫正文字位置
- painterEx->DrawText(rc, strDay, textColor, Qt::AlignCenter);
- }
- void CalendarWidgetEx::paintEvent(QPaintEvent *)
- {
- PainterEx painter(this);
- //边框和背景
- painter.setPen(Qt::transparent);
- painter.setBrush(m_bgBrushColor);
- QRect rc(rect());
- painter.DrawRoundedRect(rc, WINDOW_RADIUS);
- QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
- if(vBodyLayout != nullptr) {
- // 画导航栏,绘制上圆角
- QPainterPath path;
- path.setFillRule(Qt::WindingFill);
- QRectF tmpRc(1, 0, WINDOW_WIDTH - WINDOW_RADIUS, 40);
- path.addRoundedRect(tmpRc, WINDOW_RADIUS, WINDOW_RADIUS);
- path.addRect(QRectF(tmpRc.x(), tmpRc.y() + WINDOW_RADIUS, tmpRc.width(), tmpRc.height()));
- // painter.fillPath(path, QColor(255, 255, 255));
- painter.fillPath(path, m_bgBrushColor);
- //分割线
- QWidget* pNav = vBodyLayout->itemAt(0)->widget();
- if (nullptr != pNav) {
- int h = pNav->mapTo(this, pNav->rect().bottomRight()).y() + 2;
- // painter.SetPenOnly(QColor(0, 0, 0, 23));
- painter.setPen(m_bgPenColor);
- painter.drawLine(QPoint(0, h), QPoint(width(), h));
- }
- }
- }
- QSize CalendarWidgetEx::minimumSizeHint() const
- {
- return QSize(WINDOW_WIDTH, WINDOW_HEIGHT);
- }
- void CalendarWidgetEx::mouseMoveEvent(QMouseEvent *event)
- {
- QCalendarWidget::mouseMoveEvent(event);
- QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
- if(vBodyLayout == nullptr) return;
- QTableView *pCalendarView = dynamic_cast<QTableView*>(vBodyLayout->itemAt(4)->widget());
- if(pCalendarView == nullptr) return;
- QModelIndex index = pCalendarView->indexAt(pCalendarView->mapFromGlobal(event->globalPos()));
- QDate dateMouseOver = dateForCell(index.row(), index.column());
- if(m_dateMouseOver != dateMouseOver)
- {
- m_dateMouseOver = dateMouseOver;
- if(m_pDateScopeModel != nullptr && !m_pDateScopeModel->bLocked && m_pDateScopeModel->dtFirst.isValid())
- {
- m_pDateScopeModel->dtSecond = dateMouseOver;
- m_pDateScopeModel->Update();
- }
- update();
- }
- }
- //仅适用于: 不显示纵向表头(第几周), 且不显示横向表头(周几)
- QDate CalendarWidgetEx::dateForCell(int row, int column) const
- {
- if (row < 0 || row > 5 || column < 0 || column > 6)
- return QDate();
- const QDate refDate = referenceDate();
- if (!refDate.isValid())
- return QDate();
- const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
- if (columnForFirstOfShownMonth - 0/*m_firstColumn*/ < 1)
- row -= 1;
- const int requestedDay = 7 * (row - 0/*m_firstRow*/) + column - columnForFirstOfShownMonth - refDate.day() + 1;
- return refDate.addDays(requestedDay);
- }
- QDate CalendarWidgetEx::referenceDate() const
- {
- int refDay = 1;
- while (refDay <= 31) {
- QDate refDate(yearShown(), monthShown(), refDay);
- if (refDate.isValid())
- return refDate;
- refDay += 1;
- }
- return QDate();
- }
- int CalendarWidgetEx::columnForFirstOfMonth(const QDate &date) const
- {
- return (columnForDayOfWeek(date.dayOfWeek()) - (date.day() % 7) + 8) % 7;
- }
- int CalendarWidgetEx::columnForDayOfWeek(int day) const
- {
- if (day < 1 || day > 7)
- return -1;
- int column = day - firstDayOfWeek();
- if (column < 0)
- column += 7;
- return column;
- }
- void CalendarWidgetEx::initSkinColor()
- {
- switch (m_style)
- {
- case 0:
- m_normalTextColor = NORMAL_TEXT_BRIGHT;
- m_todayTextColor = TODAY_TEXT_BRIGHT;
- m_selectTextColor = SELECT_TEXT_BRIGHT;
- m_disableTextColor = DISABLE_TEXT_BRIGHT;
- m_splitLineColor = SPLIT_LINE_BRIGHT;
- m_selectBlockColor = SELECT_BRIGHT;
- m_hoverBlockColor = HOVER_BRIGHT;
- m_bgBrushColor = BG_BRUSH_BRIGHT;
- m_bgPenColor = BG_PEN_BRIGHT;
- break;
- case 1:
- m_normalTextColor = NORMAL_TEXT_DEEP;
- m_todayTextColor = TODAY_TEXT_DEEP;
- m_selectTextColor = SELECT_TEXT_DEEP;
- m_disableTextColor = DISABLE_TEXT_DEEP;
- m_splitLineColor = SPLIT_LINE_DEEP;
- m_selectBlockColor = SELECT_DEEP;
- m_hoverBlockColor = HOVER_DEEP;
- m_bgBrushColor = BG_BRUSH_DEEP;
- m_bgPenColor = BG_PEN_DEEP;
- break;
- default:
- break;
- }
- }
- void CalendarWidgetEx::OnClicked(const QDate &date)
- {
- if(m_modeSelection == Multi)
- {
- if(m_listMultiSelectDays.contains(date))
- {
- m_listMultiSelectDays.removeOne(date);
- }
- else
- {
- m_listMultiSelectDays.append(date);
- }
- }
- if(m_modeSelection == Scope && m_pDateScopeModel != nullptr)
- {
- if(!m_pDateScopeModel->bLocked && m_pDateScopeModel->dtFirst.isValid())
- {
- m_pDateScopeModel->dtSecond = date;
- m_pDateScopeModel->bLocked = true;
- m_pDateScopeModel->Locked();
- }
- else
- {
- m_pDateScopeModel->dtFirst = date;
- m_pDateScopeModel->dtSecond = date;
- m_pDateScopeModel->bLocked = false;
- }
- m_pDateScopeModel->Update();
- }
- update();
- }
- void CalendarWidgetEx::leaveEvent(QEvent *)
- {
- if(m_modeSelection != Scope)
- {
- //离开日历时, 清空鼠标移入状态
- m_dateMouseOver = QDate();
- update();
- }
- }
- void NoFocusStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
- {
- QStyleOption *viewOption = new QStyleOption(*option);
- viewOption->state &= (~QStyle::State_HasFocus);
- //if (element == PE_FrameFocusRect) return;
- QProxyStyle::drawPrimitive(element, viewOption, painter, widget);
- delete viewOption;
- }
|