日历(QCalendarWidget)的使用及风格样式的设置——Qt

摘自:https://blog.csdn.net/xiaopei_yan/article/details/108007941

前言
之前项目中没涉及过日历控件(QCalendarWidget),一般我是用简单的日期编辑器代替,对它的印象只存在于QtDesigner中丑的不行的日历控件。这次我要写类似企业微信的日程(如下图)功能的东西,这个就必须用到日历了(此篇博客只介绍日历的写法)。

有两种方式实现:一是自己全部重写,二呢是,修改Qt自带的控件QCalendarWidget,难易程度我肯定选二个了,不过后续我想自己重写一个日历,这样自己更有自主权。

效果图
这次先把效果图放到前边吧,对比着代码看,更容易讲解。

代码及说明
代码部分参考大佬的博客

https://blog.csdn.net/ly305750665/article/details/80092040

因为用的是Qt自带的日历控件,所以就不用操心基本功能(比如时间的管理),我们只需要将日历控件的外貌设置为我们想要的就行了。

导航栏的重写
日历自带的导航栏真心丑,所以我将原始的导航栏隐藏起来自己又重新写了一个。左右按钮我没设置风格,因为写的是Demo,就犯懒了。

setNavigationBarVisible(false);
void MyCalendarWidget::initTopWidget()
{
    QWidget* topWidget = new QWidget(this);
    topWidget->setObjectName("CalendarTopWidget");
    topWidget->setFixedHeight(40);
    topWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
 
    QHBoxLayout* hboxLayout = new QHBoxLayout;
    hboxLayout->setContentsMargins(12, 0, 12, 0);
    hboxLayout->setSpacing(4);
 
    m_leftMonthBtn  = new QPushButton(this);
    m_leftMonthBtn->setText("<");
    m_rightMonthBtn = new QPushButton(this);
    m_rightMonthBtn->setText(">");
    m_dataLabel     = new QLabel(this);
 
    m_leftMonthBtn->setObjectName("CalendarLeftMonthBtn");
    m_rightMonthBtn->setObjectName("CalendarRightMonthBtn");
    m_dataLabel->setObjectName("CalendarDataLabel");
 
    m_leftMonthBtn->setFixedSize(16, 16);
    m_rightMonthBtn->setFixedSize(16, 16);
 
    hboxLayout->addStretch();
    hboxLayout->addWidget(m_leftMonthBtn);
    hboxLayout->addWidget(m_dataLabel);
    hboxLayout->addWidget(m_rightMonthBtn);
    hboxLayout->addStretch();
    topWidget->setLayout(hboxLayout);
 
    QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
    vBodyLayout->insertWidget(0, topWidget);
 
    connect(m_leftMonthBtn,&QPushButton::clicked,this,&MyCalendarWidget::onbtnClicked);
    connect(m_rightMonthBtn,&QPushButton::clicked,this,&MyCalendarWidget::onbtnClicked);
 
    setDataLabelTimeText(selectedDate().year(), selectedDate().month());
}
 
void MyCalendarWidget::onbtnClicked()
{
    QPushButton *senderBtn = qobject_cast<QPushButton *>(sender());
    if (senderBtn == m_leftMonthBtn)
    {
        showPreviousMonth();
    }
    else if (senderBtn == m_rightMonthBtn)
    {
        showNextMonth();
    }
}
一些基础设置 
 日历这这样首先设置为中文(setLocale),这为行表头(tHorizontalHeader)的名字的中英文做铺垫:中文就是周几,星期几,英文Monday Mon.之类。我还设置了单选和周六日的风格,这些东西不仅只是表面意思,还有其他的作用。

void MyCalendarWidget::initControl()
{
    //layout()->setSizeConstraint(QLayout::SetFixedSize);//大小不随布局变化,我不需要
    setLocale(QLocale(QLocale::Chinese));//设置中文
    setNavigationBarVisible(false);//隐藏导航条
    setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);//去掉列表头
    setHorizontalHeaderFormat(QCalendarWidget::LongDayNames);//我想要星期几的行表头
    setSelectionMode(QCalendarWidget::SingleSelection);//单选
 
 
    //设置星期风格
    QTextCharFormat format;
    format.setForeground(QColor(51, 51, 51));
    format.setBackground(QColor(247,247,247));
    format.setFontFamily("Microsoft YaHei");
    format.setFontPointSize(9);
    format.setFontWeight(QFont::Medium);
    setWeekdayTextFormat(Qt::Saturday, format);
    setWeekdayTextFormat(Qt::Sunday,   format);
 
    initTopWidget();
 
    connect(this, &QCalendarWidget::currentPageChanged, [this](int year, int month){
        setDataLabelTimeText(year, month);
    });
}
先说我上面设置了日历是单选的,这个还有一个深层次的原因:我将选中的矩形改为圆形后,出现了一个问题就是,刚show出来后,在当天圆圈圈住后,前一天被矩形框住了,也就是有两个被选中了,前一天用的样式是原始的,而当天的是我新写的。我不知道什么原因造成的,所以只能将其设为单选解决此问题了。

void MyCalendarWidget::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(118, 178, 224));
        painter->drawEllipse(QRect(rect.x()+rect.width()/2-10, rect.y() + rect.height()/2-10, 20, 20));
        painter->setPen(QColor(255, 255, 255));
        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(118, 178, 224));
 
        painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        painter->restore();
    }
    else if (date < minimumDate() || date > maximumDate())
    {
 
        qDebug()<< minimumDate()<<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->drawEllipse(QRect(rect.x()+rect.width()/2-10, rect.y() + rect.height()/2-10, 20, 20));
        painter->setPen(QColor(255,0,0));
 
        painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
        painter->restore();
    }
    else
    {
        QCalendarWidget::paintCell(painter, rect, date);
 
    }
}
QSS设置 
我在上面曾说道,我通过代码只更改了周六日的风格,这是为什么呢?因为qss中我没找到将周六日红色字体改为正常的语句。然后还有一点指的注意的是:设置了weekday 的format,那么表头的format将无效。(If you also set a weekday text format, this format's foreground and background color will take precedence over the header's format.)所以这就造成我为了将周六日变为正常色,但是我就没办法将表头设为其他色了,有点遗憾。

我看了一点QCalendarWidget的源码,视图部分是QCalendarView控制的,它继承的QTableView;我之前以为QCalendarWidget的表头即为QHeaderView,后来发现不是,QCalendarView将表头隐藏,然后将第一行作为horizontalHeader,第一列作为verticalHeader,涉及到的代码有:

enum {
    RowCount = 6,
    ColumnCount = 7,
    HeaderColumn = 0,
    HeaderRow = 0,
    MinimumDayOffset = 1
};
 
QCalendarView::QCalendarView(QWidget *parent)
    : QTableView(parent),
    readOnly(false),
    validDateClicked(false)
{
    setTabKeyNavigation(false);
    setShowGrid(false);
    verticalHeader()->setVisible(false);
    horizontalHeader()->setVisible(false);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
 
 
 

QCalendarWidget QAbstractItemView{
  font-size:12px;
  font-family:Microsoft YaHei;
  font-weight:500;
  outline:0px;
}
QCalendarWidget QAbstractItemView:disabled{
  color:#D3D3D3;
}
QCalendarWidget QAbstractItemView:enabled{
  color:#333333;
}
QCalendarView#qt_calendar_calendarview {
  background-color:  #F7F7F7;           /*背景色*/
  alternate-background-color:#F7F7F7;   {/* 表头的背景颜色,为什么设置这个就有效,我不清楚*/
}
为了更好地写qss,我学会了一个dump方法,这样可以看到控件的结构和objectName.

ui->calendarWidget->dumpObjectTree();
 将打印出如下结果:

QCalendarWidget::calendarWidget 
    QVBoxLayout:: 
    QCalendarModel:: 
    QCalendarView::qt_calendar_calendarview 
        QWidget::qt_scrollarea_viewport 
        QWidget::qt_scrollarea_hcontainer 
            QScrollBar:: 
            QBoxLayout:: 
        QWidget::qt_scrollarea_vcontainer 
            QScrollBar:: 
            QBoxLayout:: 
        QStyledItemDelegate:: 
        QHeaderView:: 
            QWidget::qt_scrollarea_viewport 
            QWidget::qt_scrollarea_hcontainer 
                QScrollBar:: 
                QBoxLayout:: 
            QWidget::qt_scrollarea_vcontainer 
                QScrollBar:: 
                QBoxLayout:: 
            QItemSelectionModel:: 
        QHeaderView:: 
            QWidget::qt_scrollarea_viewport 
            QWidget::qt_scrollarea_hcontainer 
                QScrollBar:: 
                QBoxLayout:: 
            QWidget::qt_scrollarea_vcontainer 
                QScrollBar:: 
                QBoxLayout:: 
            QItemSelectionModel:: 
        QTableCornerButton:: 
        QItemSelectionModel:: 
    QWidget::qt_calendar_navigationbar 
        QPrevNextCalButton::qt_calendar_prevmonth 
        QPrevNextCalButton::qt_calendar_nextmonth 
        QToolButton::qt_calendar_monthbutton 
            QMenu:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
                QAction:: 
        QToolButton::qt_calendar_yearbutton 
        QSpinBox::qt_calendar_yearedit 
            QLineEdit::qt_spinbox_lineedit 
                QWidgetLineControl:: 
            QValidator::qt_spinboxvalidator 
        QHBoxLayout:: 
    QCalendarDelegate:: 
    QCalendarTextNavigator:: 
    QProxyStyle:: 
    QWidget::CalendarTopWidget 
        QHBoxLayout:: 
        QPushButton::CalendarLeftMonthBtn 
        QLabel::CalendarDataLabel 
        QPushButton::CalendarRightMonthBtn 
 

QCalendarWidget 样式设置

https://blog.csdn.net/wuchalilun/article/details/73613604?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

修改日历的样式,使用QSS设置,做个记录


图是借用的网友的,如图显示:需要修改的地方有大致这么5处,我们一个一个来说:

 

1. 左右两边的箭头

这个我试了qss还是没成功,因为这两个箭头跟我贴的图就重叠了,最后我就在代码中实现了,效果是一样的,如果有人知道在qss中实现,也麻烦告诉我一声

代码:

QToolButton *prevBtn = calendar->findChild<QToolButton*>(QLatin1String("qt_calendar_prevmonth"));

  QToolButton *bextBtn = calendar->findChild<QToolButton*>(QLatin1String("qt_calendar_nextmonth"));
  prevBtn->setIcon("你自己的图标");

  bextBtn->setIcon("你自己的图标");

"qt_calendar_prevmonth"名字是查看源码知道的

2. 中间白色部分


 
 QCalendarWidget QTableView 
 
 {
 
     alternate-
 background-color
 : 
 rgb
 (
 128
 , 
 128
 , 
 128
 ); //颜色自己可以改
 
 }

3. 背景色


 
 QCalendarWidget QTableView 
 
 {
 
     alternate-
 background-color
 : 
 rgb
 (
 128
 , 
 128
 , 
 128
 ); //颜色自己可以改
 
     background-color: #2F2F3E; 
 
 }
4&5. 月份 和年份
QToolButton#qt_calendar_monthbutton,#qt_calendar_yearbutton{

color: #9ea5a9; //修改字体颜色

font: 9pt simHei; //也可以修改字体

}

6.  显示月份和年份所在的导航条

    QCalendarWidget QWidget#qt_calendar_navigationbar{

//可以自己添加一些其他设置,比如边框

background-color: #2F2F3E;//这个一般设置渐变色比较多,可以自行修改

}
 

  到这就基本说完了,最后再说下,鼠标点击月份会弹出一个下拉框,默认的也不好看,其实那是个菜单,qss中设置QMenu就可以改变其背景,

  还有年份旁边有个QSpinBox也可以修改,这些都简单,网上搜下都有介绍
————————————————
版权声明:本文为CSDN博主「Ray_Chang_988」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wuchalilun/article/details/73613604

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值