Qt绘制可选择范围的日历

【日历控件设计】

在这里插入图片描述
在这里插入图片描述

#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QCalendarWidget>
#include <QHBoxLayout>
#include <QSpinBox>
#include <QPushButton>
#include <QLabel>
#include <QDate>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>
#include <QTableView>
#include <QTimer>
#include <QEvent>

enum class CaldrStat{
    Init,Click
};


class CPCustomCalendar : public QCalendarWidget {
    Q_OBJECT
public:
    CPCustomCalendar(QWidget *parent = nullptr)
        : QCalendarWidget(parent)
        , m_startDate(QDate())
        , m_endDate(QDate())
    {
        setGridVisible(true);
        setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
        connect(this, &QCalendarWidget::clicked,this,&CPCustomCalendar::handleDateSelection);
    }



protected:
    void paintCell(QPainter *painter, const QRect &rect, const QDate date) const override {
        QCalendarWidget::paintCell(painter, rect, date);

        if (!m_startDate.isValid()  || !m_endDate.isValid()) return;

        painter->setRenderHint(QPainter::SmoothPixmapTransform);
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setRenderHint(QPainter::TextAntialiasing);//文字抗锯齿

        auto radius = rect.height() >> 1;
        if (date == m_startDate || date == m_endDate) {
            painter->setBrush(QColor(0x0155FF));
            painter->setPen(Qt::NoPen);
            painter->drawRoundedRect(rect, radius, radius);
            QRect _rect= date == m_endDate ? rect.adjusted(0, 0, -radius, 0)
                                           : rect.adjusted(radius, 0, 0, 0);
            painter->drawRect(_rect);
            painter->setPen(Qt::white);
            painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        }
        else if (date > m_startDate && date < m_endDate) {
            painter->fillRect(rect, QColor(0xE4F0FF));
            painter->setPen(QColor(0x435C86));
            painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        }
    }

private slots:
    void handleDateSelection() {
        isClicked = !isClicked;
        if (isClicked) {
            m_startDate = selectedDate();
            m_endDate = QDate();
            setFocus();
        } else{
            m_endDate = selectedDate();
            clearFocus();
            if (m_endDate < m_startDate)
                std::swap(m_startDate, m_endDate);
            emit rangeChanged(m_startDate, m_endDate);
        }
        updateCells();
    }

signals:
    void rangeChanged(const QDate &start, const QDate &end);

private:
    QDate m_startDate;
    QDate m_endDate;
    QTableView *tableView = nullptr;
    bool   isClicked{false};
    CaldrStat  stat{CaldrStat::Init};
};

class DateRangePicker : public QWidget {
    Q_OBJECT
public:
    DateRangePicker(QWidget *parent = nullptr) : QWidget(parent) {
        selectedDaysLabel = new QLabel("已选0天", this);
        calendar = new CPCustomCalendar(this);
        calendar->setMinimumDate(QDate(2023, 1, 1));
        calendar->setMaximumDate(QDate(2025, 12, 31));
        connect(calendar, &CPCustomCalendar::rangeChanged, this, &DateRangePicker::updateDayCount);

        QVBoxLayout *mainLayout = new QVBoxLayout(this);
        mainLayout->addWidget(calendar);
        mainLayout->addWidget(selectedDaysLabel);

    }

private slots:
    void updateDayCount(const QDate &start, const QDate &end) {
        if (start.isValid() && end.isValid()) {
            int days = start.daysTo(end) + 1;
            selectedDaysLabel->setText(QString("已选%1天").arg(days));
        } else {
            selectedDaysLabel->setText("已选0天");
        }
    }

private:
    CPCustomCalendar *calendar;
    QLabel *selectedDaysLabel;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    DateRangePicker picker;
    picker.setWindowTitle("日期时间选择控件");
    picker.resize(400, 350);
    picker.show();

    return app.exec();
}

#include "main.moc"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值