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"