| 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;}
 |