• 3217阅读
  • 4回复

Qt编写自定义控件65-光晕日历 [复制链接]

上一主题 下一主题
离线liudianwu
 

只看楼主 倒序阅读 楼主  发表于: 2019-10-10
一、前言
操作系统的更新迭代速度非常快,基本上三五年就有个新版本出来,WIN10操作系统还是一个比较成功的系统,据说现在市场份额越来越大,XP的份额已经很小,WIN7的份额也在逐步减少,在最新的WIN10系统中,右下角有个日历控件,还是自带农历的,这个本地化做的蛮好的,鼠标移上去还有光晕背景效果,体验非常赏心悦目,于是打算用Qt也高仿一个。
本控件的技术难点有两个,一个是根据当前月份自动排列星期和日期,这个需要自动计算的,难点二是绘制光晕背景,需要用到painter中的图像叠加模式setCompositionMode,设置好图像叠加模式以后,可以将多个绘制重叠,按照设定的规则组合,比如将光晕背景绘制在背后。

二、实现的功能
* 1:可设置背景颜色
* 2:可设置光晕颜色
* 3:可设置文字颜色
* 4:可设置选中日期背景
* 5:光晕跟随鼠标移动

三、效果图



四、头文件代码
  1. #ifndef SHADOWCALENDAR_H
  2. #define SHADOWCALENDAR_H
  3. /**
  4. * 光晕日历控件 作者:雨田哥(QQ:3246214072) 整理:feiyangqingyun(QQ:517216493) 2019-10-07
  5. * 1:可设置背景颜色
  6. * 2:可设置光晕颜色
  7. * 3:可设置文字颜色
  8. * 4:可设置选中日期背景
  9. * 5:光晕跟随鼠标移动
  10. */
  11. #include <QWidget>
  12. #include <QDate>
  13. #ifdef quc
  14. #if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
  15. #include <QtDesigner/QDesignerExportWidget>
  16. #else
  17. #include <QtUiPlugin/QDesignerExportWidget>
  18. #endif
  19. class QDESIGNER_WIDGET_EXPORT ShadowCalendar : public QWidget
  20. #else
  21. class ShadowCalendar : public QWidget
  22. #endif
  23. {
  24.     Q_OBJECT
  25.     Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor)
  26.     Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor)
  27.     Q_PROPERTY(QColor shadowColor READ getShadowColor WRITE setShadowColor)
  28.     Q_PROPERTY(QColor selectColor READ getSelectColor WRITE setSelectColor)
  29. public:
  30.     struct DateItem {
  31.         int year;
  32.         int month;
  33.         int day;
  34.         DateItem()
  35.         {
  36.             year = -1;
  37.             month = -1;
  38.             day = -1;
  39.         }
  40.     };
  41.     explicit ShadowCalendar(QWidget *parent = 0);
  42.     ~ShadowCalendar();
  43. public:
  44.     void updateCalendar(const QDate &selectDate);
  45. protected:
  46.     void leaveEvent(QEvent *);
  47.     void mouseMoveEvent(QMouseEvent *);
  48.     void paintEvent(QPaintEvent *);
  49. private:
  50.     QColor bgColor;             //背景颜色
  51.     QColor textColor;           //文字颜色
  52.     QColor shadowColor;         //光晕颜色
  53.     QColor selectColor;         //选中颜色
  54.     QDate selectDate;           //今天日期
  55.     DateItem dateItem[6][7];    //日期数组
  56. public:
  57.     QColor getBgColor()         const;
  58.     QColor getTextColor()       const;
  59.     QColor getShadowColor()     const;
  60.     QColor getSelectColor()     const;
  61.     QSize sizeHint()            const;
  62.     QSize minimumSizeHint()     const;
  63. public Q_SLOTS:
  64.     //设置背景颜色+文字颜色+光晕颜色+选中颜色
  65.     void setBgColor(const QColor &bgColor);
  66.     void setTextColor(const QColor &textColor);
  67.     void setShadowColor(const QColor &shadowColor);
  68.     void setSelectColor(const QColor &selectColor);
  69. };
  70. #endif // SHADOWCALENDAR_H

五、核心代码
  1. void ShadowCalendar::paintEvent(QPaintEvent *)
  2. {
  3.     QPainter painter(this);
  4.     painter.setRenderHints(QPainter::Antialiasing);
  5.     int sw = 336;
  6.     int sh = 336;
  7.     qreal scaleX = this->width() * 1.0 / sw;
  8.     qreal scaleY = this->height() * 1.0 / sh;
  9.     painter.scale(scaleX, scaleY);
  10.     painter.setPen(Qt::NoPen);
  11.     painter.fillRect(0, 0, sw, sh, bgColor);
  12.     qreal iw = sw / 7.0;
  13.     qreal ih = sh / 7.0;
  14.     //mask
  15.     QPointF globalpoint = this->mapFromGlobal(QCursor::pos());
  16.     const QPointF &point = QPointF(globalpoint.x() / scaleX, globalpoint.y() / scaleY);
  17.     //绘制光晕背景
  18.     if (this->underMouse()) {
  19.         int effectradius = 58;
  20.         painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
  21.         QRadialGradient radialGrad(point, effectradius);
  22.         radialGrad.setColorAt(0, QColor(0, 0, 0, 120));
  23.         radialGrad.setColorAt(1, QColor(0, 0, 0, 255));
  24.         painter.setBrush(radialGrad);
  25.         painter.drawEllipse(point, effectradius, effectradius);
  26.         painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
  27.         painter.setBrush(Qt::NoBrush);
  28.         for (int row = 0; row < 6; row++) {
  29.             for (int column = 0; column < 7; column++) {
  30.                 QRectF rect = QRectF(column * iw, (row + 1) * ih, iw, ih).adjusted(3, 3, -3, -3);
  31.                 if (rect.contains(point)) {
  32.                     painter.save();
  33.                     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
  34.                     painter.setPen(QPen(QColor(220, 220, 220, 160), 2));
  35.                     painter.drawRoundedRect(rect, 2, 2);
  36.                     painter.restore();
  37.                     continue;
  38.                 } else {
  39.                     painter.setPen(QPen(shadowColor, 2));
  40.                 }
  41.                 painter.drawRoundedRect(rect, 2, 2);
  42.             }
  43.         }
  44.         //绘制圆形的光晕底层背景
  45.         painter.fillRect(0, 0, sw, sh, QColor(200, 200, 200, 50));
  46.     }
  47.     //绘制头部中文数字,先设置图像叠加模式为源在上面
  48.     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
  49.     painter.setPen(textColor);
  50.     QStringList listHead;
  51.     listHead << "一" << "二" << "三" << "四" << "五" << "六" << "日";
  52.     for (int i = 0; i < 7; i++) {
  53.         painter.drawText(i * iw, 0, iw, ih, Qt::AlignCenter, listHead.at(i));
  54.     }
  55.     //绘制日期
  56.     for (int row = 0; row < 6; row++) {
  57.         for (int column = 0; column < 7; column++) {
  58.             if (dateItem[row][column].day > 0) {
  59.                 QRectF rect = QRectF(column * iw, (row + 1) * ih, iw, ih).adjusted(3, 3, -3, -3);
  60.                 //如果是选中的日期则突出绘制背景
  61.                 if (QDate::currentDate() == QDate(dateItem[row][column].year, dateItem[row][column].month, dateItem[row][column].day)) {
  62.                     painter.setPen(QPen(selectColor, 2));
  63.                     painter.setBrush(Qt::NoBrush);
  64.                     //如果和光晕效果重叠则边框高亮
  65.                     if (rect.contains(point)) {
  66.                         painter.setPen(QPen(selectColor.lighter(), 2));
  67.                     }
  68.                     //绘制圆角边框
  69.                     painter.drawRoundedRect(rect, 2, 2);
  70.                     //绘制里边背景
  71.                     painter.setPen(Qt::NoPen);
  72.                     painter.setBrush(selectColor);
  73.                     painter.drawRoundedRect(rect.adjusted(4, 4, -4, -4), 2, 2);
  74.                 }
  75.                 painter.setPen(textColor);
  76.                 painter.drawText(rect, Qt::AlignCenter, QString::number(dateItem[row][column].day));
  77.             }
  78.         }
  79.     }
  80. }

六、控件介绍
1. 超过160个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.13的任何Qt版本,支持mingw、msvc、gcc等编译器,支持任意操作系统比如windows+linux+mac+嵌入式linux等,不乱码,可直接集成到Qt  Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
6. 每个控件默认配色和demo对应的配色都非常精美。
7. 超过130个可见控件,6个不可见控件。
8. 部分控件提供多种样式风格选择,多种指示器样式选择。
9. 所有控件自适应窗体拉伸变化。
10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
13. 所有控件最后生成一个动态库文件(dll或者so等),可以直接集成到qtcreator中拖曳设计使用。
14. 目前已经有qml版本,后期会考虑出pyqt版本,如果用户需求量很大的话。
15. 自定义控件插件开放动态库使用(永久免费),无任何后门和限制,请放心使用。
16. 目前已提供32个版本的dll,其中qt_5_7_0_mingw530_32这个版本会一直保证最新的完整的。
17. 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
18. Qt入门书籍推荐霍亚飞的《Qt Creator快速入门》《Qt5编程入门》,Qt进阶书籍推荐官方的《C++ GUI Qt4编程》。
19. 强烈推荐程序员自我修养和规划系列书《大话程序员》《程序员的成长课》《解忧程序员》,受益匪浅,受益终生!
20. SDK地址:[https://gitee.com/feiyangqingyun/QUCSDK](https://gitee.com/feiyangqingyun/QUCSDK) [https://github.com/feiyangqingyun/qucsdk](https://github.com/feiyangqingyun/qucsdk)
欢迎关注微信公众号:Qt实战 (各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发)QQ:517216493  WX:feiyangqingyun  QQ群:751439350
离线九重水

只看该作者 1楼 发表于: 2019-10-10
你这个不行。
到了最下面一行日历,还显示9格的光晕。认真点完善一下。没有就别显示了。

只看该作者 2楼 发表于: 2019-10-10
回 九重水 的帖子
九重水:你这个不行。[表情]
到了最下面一行日历,还显示9格的光晕。认真点完善一下。没有就别显示了。 (2019-10-10 11:04) 

你这个不行。
到了最下面一行日历,还显示9格的光晕。认真点完善一下。没有就别显示了。
离线305750665

只看该作者 3楼 发表于: 2019-10-10
回 雨田小老弟 的帖子
雨田小老弟:你这个不行。
到了最下面一行日历,还显示9格的光晕。认真点完善一下。没有就别显示了。 (2019-10-10 11:47) 

  雨田小老弟来砸场子的?
雨田哥: 群号:853086607
QQ: 3246214072

刘典武-feiyangqingyun:专业各种自定义控件编写+UI定制+输入法定制+视频监控+工业控制+仪器仪表+嵌入式linux+各种串口网络通信,童叟无欺,量大从优,欢迎咨询购买定制!QQ:517216493
离线15927174837

只看该作者 4楼 发表于: 2019-10-23
为什么自定义控件做完后,自己使用一直报错没有头文件
快速回复
限100 字节
 
上一个 下一个