You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子类化QCalendarWidget时paintCell()函数的Painter错误求助

解决QCalendarWidget自定义绘制的Painter错误问题

你的问题核心是对Qt的绘制机制理解有偏差,QPainter的创建和使用必须遵循Qt的绘制生命周期,不能随意在构造函数里创建,也不能直接手动调用paintCell。下面一步步帮你修正:

错误原因拆解

  • 构造函数里创建QPainter并绑定到this:此时Widget还未进入绘制流程,没有可用的paint engine,所以触发Paint device returned engine == 0错误。
  • 手动调用paintCell(painter, rect(),date):paintCell是Qt框架在绘制日历单元格时自动调用的方法,你直接调用时,要么Painter未激活,要么绘制上下文不正确。
  • 没有存储需要标记的日期集合:你的setHolidays只能传单个日期,还没法支持多个日期标记。

修正后的代码实现

首先调整类的定义,添加一个存储标记日期的集合,移除不必要的painter成员:

// MyCalendar.h
#include <QCalendarWidget>
#include <QSet>
#include <QDate>

class MyCalendar : public QCalendarWidget
{
    Q_OBJECT
public:
    explicit MyCalendar(QWidget *parent = nullptr);
    
    // 修改为支持添加多个日期的方法
    void addHoliday(const QDate& date);
    void clearHolidays();

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

private:
    QSet<QDate> m_holidays; // 存储需要标记的日期
};

然后实现cpp文件:

// MyCalendar.cpp
#include "MyCalendar.h"
#include <QPainter>

MyCalendar::MyCalendar(QWidget *parent) : QCalendarWidget(parent)
{
    // 这里不需要创建QPainter!
}

void MyCalendar::addHoliday(const QDate& date)
{
    m_holidays.insert(date);
    update(); // 触发重绘,让框架重新调用paintCell更新所有单元格
}

void MyCalendar::clearHolidays()
{
    m_holidays.clear();
    update();
}

void MyCalendar::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
{
    // 先判断当前日期是否需要标记
    if (m_holidays.contains(date)) {
        painter->setBrush(Qt::red);
        // 先绘制背景(可选,也可以先调用父类再叠加)
        painter->drawRect(rect);
    }
    
    // 调用父类的paintCell绘制默认的日历内容(日期文字等)
    QCalendarWidget::paintCell(painter, rect, date);
}

关键修正点说明

  1. 移除成员QPainter:paintCell参数里的painter是Qt框架已经激活好的,直接用就行,不需要自己创建。框架会在绘制每个单元格时自动传入正确的Painter对象,确保绘制上下文有效。
  2. 用集合存储标记日期:QSet<QDate>可以高效判断某个日期是否需要标记,支持添加多个日期。
  3. 通过update()触发重绘:当你添加/移除标记日期后,调用update()让Qt重新绘制日历,这样paintCell会被自动调用,更新所有单元格的显示。
  4. 绘制顺序:先绘制自定义的标记(比如红色背景),再调用父类方法绘制默认内容,这样日期文字会显示在红色背景上;如果想让标记叠加在默认内容上,可以调换顺序。

使用示例

在你的主代码里,这样调用:

MyCalendar* calendar = new MyCalendar(this);
calendar->addHoliday(QDate(2024, 10, 1));
calendar->addHoliday(QDate(2024, 12, 25));

这样这两个日期就会被标记成红色背景啦。

内容的提问来源于stack exchange,提问作者karollo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:15:08