![32f710643e0d0c6b19441ccb1845551c.png](https://i-blog.csdnimg.cn/blog_migrate/c405cdf0efd19660e6b6fecdfd22ef98.jpeg)
总第48篇
本文主要总结一下在Qt
项目中,如何绘制类似Win10
系统中的日历光晕效果,并给出绘制代码,方便以后在项目中学习与参考。
在Win10
系统中,光晕日历的效果如下图所示。
![d9ce9eaa0c7ed0c004eb44d91b8a2774.gif](https://i-blog.csdnimg.cn/blog_migrate/b74011c87537fb78e30ea56fa6ca9681.gif)
用Qt
来绘制这个控件有两个难点,一个是要自己计算当前月份的日期并自动排列成星期,二是绘制这种光晕背景。其中绘制光晕效果要用到QPainter
的图像组合模式,通过官方文档,可以看到,QPainter
有多种图像组合模式,可通过接口setCompositionMode()
接口来设置。下图展示了几种基本的图像组合模式的效果。
![bdc66d06f568ef5423205237754ea9e5.png](https://i-blog.csdnimg.cn/blog_migrate/f7cd4fac9dfbdd7ecf56c6f2fd6ae637.jpeg)
不多说了,上一下核心代码。下面是头文件的定义,提供了设置背景颜色、光晕颜色、文字颜色、日期背景等接口。
#ifndef SHADOWCALENDAR_H
#define SHADOWCALENDAR_H
#include <QWidget>
#include <QDate>
class ShadowCalendar : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor)
Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor)
Q_PROPERTY(QColor shadowColor READ getShadowColor WRITE setShadowColor)
Q_PROPERTY(QColor selectColor READ getSelectColor WRITE setSelectColor)
public:
struct DateItem {
int year;
int month;
int day;
DateItem()
{
year = -1;
month = -1;
day = -1;
}
};
explicit ShadowCalendar(QWidget *parent = 0);
~ShadowCalendar();
public:
void updateCalendar(const QDate &selectDate);
protected:
void leaveEvent(QEvent *);
void mouseMoveEvent(QMouseEvent *);
void paintEvent(QPaintEvent *);
private:
QColor bgColor; //背景颜色
QColor textColor; //文字颜色
QColor shadowColor; //光晕颜色
QColor selectColor; //选中颜色
QDate selectDate; //今天日期
DateItem dateItem[6][7]; //日期数组
public:
QColor getBgColor() const;
QColor getTextColor() const;
QColor getShadowColor() const;
QColor getSelectColor() const;
public Q_SLOTS:
//设置背景颜色+文字颜色+光晕颜色+选中颜色
void setBgColor(const QColor &bgColor);
void setTextColor(const QColor &textColor);
void setShadowColor(const QColor &shadowColor);
void setSelectColor(const QColor &selectColor);
};
#endif // SHADOWCALENDAR_H
源文件里的核心绘制代码示例如下:
void ShadowCalendar::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
int sw = 336;
int sh = 336;
qreal scaleX = this->width() * 1.0 / sw;
qreal scaleY = this->height() * 1.0 / sh;
painter.scale(scaleX, scaleY);
painter.setPen(Qt::NoPen);
painter.fillRect(0, 0, sw, sh, bgColor);
qreal iw = sw / 7.0;
qreal ih = sh / 7.0;
//mask
QPointF globalpoint = this->mapFromGlobal(QCursor::pos());
const QPointF &point = QPointF(globalpoint.x() / scaleX, globalpoint.y() / scaleY);
//绘制光晕背景
if (this->underMouse()) {
int effectradius = 58;
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
QRadialGradient radialGrad(point, effectradius);
radialGrad.setColorAt(0, QColor(0, 0, 0, 120));
radialGrad.setColorAt(1, QColor(0, 0, 0, 255));
painter.setBrush(radialGrad);
painter.drawEllipse(point, effectradius, effectradius);
painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
painter.setBrush(Qt::NoBrush);
for (int row = 0; row < 6; row++) {
for (int column = 0; column < 7; column++) {
QRectF rect = QRectF(column * iw, (row + 1) * ih, iw, ih).adjusted(3, 3, -3, -3);
if (rect.contains(point)) {
painter.save();
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.setPen(QPen(QColor(220, 220, 220, 160), 2));
painter.drawRoundedRect(rect, 2, 2);
painter.restore();
continue;
} else {
painter.setPen(QPen(shadowColor, 2));
}
painter.drawRoundedRect(rect, 2, 2);
}
}
//绘制圆形的光晕底层背景
painter.fillRect(0, 0, sw, sh, QColor(200, 200, 200, 50));
}
//绘制头部中文数字,先设置图像叠加模式为源在上面
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.setPen(textColor);
QStringList listHead;
listHead << "一" << "二" << "三" << "四" << "五" << "六" << "日";
for (int i = 0; i < 7; i++) {
painter.drawText(i * iw, 0, iw, ih, Qt::AlignCenter, listHead.at(i));
}
//绘制日期
for (int row = 0; row < 6; row++) {
for (int column = 0; column < 7; column++) {
if (dateItem[row][column].day > 0) {
QRectF rect = QRectF(column * iw, (row + 1) * ih, iw, ih).adjusted(3, 3, -3, -3);
//如果是选中的日期则突出绘制背景
if (QDate::currentDate() == QDate(dateItem[row][column].year, dateItem[row][column].month, dateItem[row][column].day)) {
painter.setPen(QPen(selectColor, 2));
painter.setBrush(Qt::NoBrush);
//如果和光晕效果重叠则边框高亮
if (rect.contains(point)) {
painter.setPen(QPen(selectColor.lighter(), 2));
}
//绘制圆角边框
painter.drawRoundedRect(rect, 2, 2);
//绘制里边背景
painter.setPen(Qt::NoPen);
painter.setBrush(selectColor);
painter.drawRoundedRect(rect.adjusted(4, 4, -4, -4), 2, 2);
}
painter.setPen(textColor);
painter.drawText(rect, Qt::AlignCenter, QString::number(dateItem[row][column].day));
}
}
}
}
其程序运行的结果如下图所示:
![c61a01e911bf83654b4c37086d32cddf.gif](https://i-blog.csdnimg.cn/blog_migrate/ab7df1ae4eea3f5925657a561efc0bd6.gif)
上面这种绘制方法只是提供了一种思路,为大家提供参考,更好的实现方法,可以在项目开发过程进行精进探索。
本文到此结束!
如果对你有帮助,请随手 点赞 或 点喜欢!关注本专栏,更多干货与你分享。
=======================================================
欢迎【关注、私信 @武三郎】。我们一起交流一起进步。