【QT】自定义日历弹窗

一、构想

自定义日历弹窗的制作主要是分为两部分,1、自定义日历,2、点击LineEdit时,将日历窗口弹出来。首先针对如何自定义日历制定思路,通过上网查询 QT自带了一个日历类QCalendarWidget,那就好办了,只需要自定义日历时继承这个日历类,再通过QPainter重新绘制。针对点击LineEdit时日历弹出来,要知道LineEdit没有点击事件的,那这样的话我们需要给它安装事件过滤器installEventFilter

二、效果展示

图左为QT自带的日历,图右则是自定义的日历效果图

                      

三、实现过程

日历跟lineEdit的数据交互是通过信号与槽的方式。

3.1  自定义日历的主要代码

#include "qcustomcalendartimewidget.h"
#include <QLocale>
#include <QPainter>
#include <QTextCharFormat>
#include <QProxyStyle>
#include <QTableView>
#include <QLayout>
#include <QPushButton>
#include <QLabel>
#include <QDebug>
#include <QMouseEvent>
#include <QCalendarWidget>
#include <QLabel>

QCustomCalendarTimeWidget::QCustomCalendarTimeWidget(QWidget *parent)
    : QCalendarWidget (parent)

{
    this->resize(350,250);
    initControl();
}
//鼠标事件 作用是让日历弹窗能够移动
void QCustomCalendarTimeWidget::mouseMoveEvent(QMouseEvent *e)
{
    if (mousePressed & (e->buttons() & Qt::LeftButton)) {
        this->move(e->globalPos() - mousePoint);
        e->accept();
    }
}
void QCustomCalendarTimeWidget::mousePressEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton) {
        mousePressed = true;
        mousePoint = e->globalPos() - this->pos();
        e->accept();
    }
}

void QCustomCalendarTimeWidget::mouseReleaseEvent(QMouseEvent *)
{
    mousePressed = false;
}

//初始化日历界面
void QCustomCalendarTimeWidget::initControl()
{
    //设置日历为中文
    this->setLocale(QLocale::Chinese);
    setNavigationBarVisible(false);
    setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
    setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
    //设置第一天为星期一
    QCalendarWidget::setFirstDayOfWeek(Qt::Monday);

    QTextCharFormat format;
    format.setForeground(QColor(160, 160, 160));
    format.setBackground(QColor(255, 255, 255));

    setHeaderTextFormat(format);
    //重绘日历上部栏
    initTopWidget();

    connect(this, &QCalendarWidget::currentPageChanged, [this](int year, int month){
        setDataLabelTimeText(year, month);
    });
    //日历双击响应事件
    connect(this, &QCalendarWidget::activated , this, &QCustomCalendarTimeWidget::setDate);
}
//发送时间给调用者
void QCustomCalendarTimeWidget::setDate()
{
    //通过信号将选择的时间发送出去
    emit signalSetCalendarTime(this->selectedDate());
    qDebug()<<"时间为: "<<this->selectedDate();

}
void QCustomCalendarTimeWidget::setDataLabelTimeText(int year, int month)
{
    m_dataLabel->setText(QStringLiteral("%1年%2月").arg(year).arg(month));
}
//绘制日历上部栏
void QCustomCalendarTimeWidget::initTopWidget()
{
    QWidget* topWidget = new QWidget(this);
    topWidget->setFixedHeight(40);
    topWidget->setSizePolicy(QSizePolicy::Preferred,
                             QSizePolicy::Fixed);

    QHBoxLayout* hboxLayout = new QHBoxLayout;
    hboxLayout->setContentsMargins(12, 0, 12, 0);
    hboxLayout->setSpacing(4);

    m_leftYearBtn   = new QPushButton(this);
    m_leftMonthBtn  = new QPushButton(this);
    m_rightYearBtn  = new QPushButton(this);
    m_rightMonthBtn = new QPushButton(this);
    m_dataLabel     = new QLabel(this);
    QString qss = "QLabel{font-size:18px;font-family:PingFang SC;}";
    m_dataLabel->setStyleSheet(qss);

    qss = "QPushButton{border-image:url(:/image/previousyear.png);}"
                  "QPushButton:hover{border-image: url(:/image/previousyear-hover.png);}";
    m_leftYearBtn->setFixedSize(16, 16);
    m_leftYearBtn->setStyleSheet(qss);
    m_leftYearBtn->setToolTip(tr("上一年"));

    qss = "QPushButton{border-image:url(:/image/previousmonth.png);}"
                      "QPushButton:hover{border-image: url(:/image/previous-hover.png);}";
    m_leftMonthBtn->setFixedSize(16, 16);
    m_leftMonthBtn->setStyleSheet(qss);
    m_leftMonthBtn->setToolTip(tr("上一月"));

    m_rightYearBtn->setFixedSize(16, 16);
    qss = "QPushButton{border-image:url(:/image/nextyear.png);}"
                      "QPushButton:hover{border-image: url(:/image/nextyear-hover.png);}";
    m_rightYearBtn->setStyleSheet(qss);
    m_rightYearBtn->setToolTip(tr("下一年"));

    m_rightMonthBtn->setFixedSize(16, 16);
    qss = "QPushButton{border-image:url(:/image/nextmonth.png);}"
                      "QPushButton:hover{border-image: url(:/image/nextmonth-hover.png);}";
    m_rightMonthBtn->setStyleSheet(qss);
    m_rightMonthBtn->setToolTip(tr("下一月"));

    hboxLayout->addWidget(m_leftYearBtn);
    hboxLayout->addWidget(m_leftMonthBtn);
    hboxLayout->addStretch();
    hboxLayout->addWidget(m_dataLabel);
    hboxLayout->addStretch();
    hboxLayout->addWidget(m_rightMonthBtn);
    hboxLayout->addWidget(m_rightYearBtn);
    topWidget->setStyleSheet("background-color: rgb(170, 170, 170");
    topWidget->setLayout(hboxLayout);

    QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
    vBodyLayout->insertWidget(0, topWidget);

    connect(m_leftYearBtn,   SIGNAL(clicked()),  this, SLOT(onbtnClicked()));
    connect(m_leftMonthBtn,  SIGNAL(clicked()),  this, SLOT(onbtnClicked()));
    connect(m_rightYearBtn,  SIGNAL(clicked()),  this, SLOT(onbtnClicked()));
    connect(m_rightMonthBtn, SIGNAL(clicked()),  this, SLOT(onbtnClicked()));
    //显示当前的年 月
    setDataLabelTimeText(selectedDate().year(), selectedDate().month());
}

//响应上部栏四个按钮的事件
void QCustomCalendarTimeWidget::onbtnClicked()
{
    QPushButton *senderBtn = qobject_cast<QPushButton *>(sender());
    if (senderBtn == m_leftYearBtn)
    {
        showPreviousYear();
    }
    else if (senderBtn == m_leftMonthBtn)
    {
        showPreviousMonth();
    }
    else if (senderBtn == m_rightYearBtn)
    {
        showNextYear();
    }
    else if (senderBtn == m_rightMonthBtn)
    {
        showNextMonth();
    }
}

//绘制日历中间部分 当前点击的时间,当前时间的样式,通过QPainter
void QCustomCalendarTimeWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
{

    if (date == selectedDate())
    {
        painter->save();
        //抗锯齿
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setPen(Qt::NoPen);
        painter->setBrush(QColor(0, 145, 255));

        painter->drawEllipse(rect.x()+9, rect.y()+1, rect.width()-17, rect.height()-2);
        painter->setPen(QColor(255, 255, 255));

        painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        painter->restore();
    }
    else if (date < minimumDate() || date > maximumDate())
    {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setPen(Qt::NoPen);
        painter->setBrush(QColor(249, 249, 249));

        painter->drawRect(rect.x(), rect.y() + 3, rect.width(), rect.height() - 6);
        painter->setPen(QColor(220, 220, 220));

        painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        painter->restore();
    }
    else if (date == QDate::currentDate())
    {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setPen(QColor(0, 161, 255));
        painter->drawEllipse(rect.x()+9, rect.y()+1, rect.width()-17, rect.height()-2);
        painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        painter->restore();
    }
    else
    {
        QCalendarWidget::paintCell(painter, rect, date);
    }
}

3.2 点击LineEdit弹出日历的主要代码

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QHBoxLayout>
#include <QLabel>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    datePickerWidget = nullptr;
    initUI();
}

MainWindow::~MainWindow()
{
    delete ui;
}
//LineEdit的左边贴一张图
void MainWindow::initUI()
{
    QLabel *iconLabel = new QLabel(this);
    iconLabel->setFixedSize(24,24);
    iconLabel->setPixmap(QPixmap(":/image/calendarico.png"));
    QHBoxLayout *hLayout = new QHBoxLayout();
    hLayout->addSpacing(12);
    hLayout->addWidget(iconLabel);
    hLayout->addSpacing(10);
    hLayout->addStretch();

    ui->lineEdit->setLayout(hLayout);
    ui->lineEdit->installEventFilter(this);

}

//时间过滤响应函数
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    //lineEdit被点击
    if(qobject_cast<QLineEdit *>(obj) == ui->lineEdit &&
            event->type() == QEvent::MouseButtonPress) {
        if(!datePickerWidget)
            datePickerWidget = new QCustomCalendarTimeWidget(this);
        connect(datePickerWidget, &QCustomCalendarTimeWidget::signalSetCalendarTime, this, &MainWindow::SetDate);
        datePickerWidget->show();
    }
    return QObject::eventFilter(obj,event);
}

//接收数据的槽函数
void MainWindow::SetDate(const QDate& date)
{
    ui->lineEdit->setText(date.toString("yyyy-MM-dd"));
    datePickerWidget->close();
}

问题咨询及项目源码请加群:

QQ群

名称:IT项目交流群

群号:245022761

 

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值