一、前言

这个控件一开始打算用样式表来实现,经过初步的探索,后面发现还是不够智能以及不能完全满足需求,比如要在此控件设置多个角标,这个用QSS就很难实现,后面才慢慢研究用QPainter来绘制,我记得当时接到这个定制控件任务的时候是2016年,那时候对QPainter的使用还不是很熟悉,也就是从此控件开始,逐步研究QPainter的绘制,把所有的内置函数都使用一遍,最终用的越来越熟悉,使得后来到了心中有坐标,万物皆painter的境界,可能就像武林中所说的打通了任督二脉吧。

本控件除了可以设置常规的圆角角度,边框宽度,边框颜色,正常颜色,按下颜色以外,还可以设置各个角标和正文文字内容/字体/对齐方式/颜色,同时还要提供三种颜色展示模式,松开按下两种颜色,按下松开颜色上下交替,按下松开颜色渐变交替。QLinearGradient是个好东西,各种颜色交替效果全靠它来实现。

二、实现的功能

  • 1:可设置圆角角度,边框宽度
  • 2:可设置角标和正文文字内容/字体/对齐方式/颜色
  • 3:可设置边框颜色,正常颜色,按下颜色
  • 4:可设置背景图片
  • 5:可设置按钮颜色模式

三、效果图

四、头文件代码

#ifndef COLORBUTTON_H
#define COLORBUTTON_H /**
* 多样式超级按钮控件 作者:feiyangqingyun(QQ:517216493) 2017-9-24
* 1:可设置圆角角度,边框宽度
* 2:可设置角标和正文文字内容/字体/对齐方式/颜色
* 3:可设置边框颜色,正常颜色,按下颜色
* 4:可设置背景图片
* 5:可设置按钮颜色模式
*/ #include <QWidget> #ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif class QDESIGNER_WIDGET_EXPORT ColorButton : public QWidget
#else
class ColorButton : public QWidget
#endif {
Q_OBJECT
Q_ENUMS(ColorMode)
Q_ENUMS(TextAlign)
Q_PROPERTY(int borderRadius READ getBorderRadius WRITE setBorderRadius)
Q_PROPERTY(int borderWidth READ getBorderWidth WRITE setBorderWidth)
Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor) Q_PROPERTY(bool showSuperText READ getShowSuperText WRITE setShowSuperText)
Q_PROPERTY(QString superText READ getSuperText WRITE setSuperText)
Q_PROPERTY(QFont superTextFont READ getSuperTextFont WRITE setSuperTextFont)
Q_PROPERTY(TextAlign superTextAlign READ getSuperTextAlign WRITE setSuperTextAlign)
Q_PROPERTY(QColor superTextColor READ getSuperTextColor WRITE setSuperTextColor) Q_PROPERTY(QString text READ getText WRITE setText)
Q_PROPERTY(QFont textFont READ getTextFont WRITE setTextFont)
Q_PROPERTY(TextAlign textAlign READ getTextAlign WRITE setTextAlign)
Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) Q_PROPERTY(QColor normalColor READ getNormalColor WRITE setNormalColor)
Q_PROPERTY(QColor pressedColor READ getPressedColor WRITE setPressedColor) Q_PROPERTY(bool canMove READ getCanMove WRITE setCanMove)
Q_PROPERTY(QPixmap bgImage READ getBgImage WRITE setBgImage)
Q_PROPERTY(ColorMode colorMode READ getColorMode WRITE setColorMode) public:
enum ColorMode {
ColorMode_Normal = 0, //松开按下两种颜色
ColorMode_Replace = 1, //按下松开颜色上下交替
ColorMode_Shade = 2 //按下松开颜色渐变交替
}; enum TextAlign {
TextAlign_Top_Left = 0,
TextAlign_Top_Center = 1,
TextAlign_Top_Right = 2,
TextAlign_Center_Left = 3,
TextAlign_Center_Center = 4,
TextAlign_Center_Right = 5,
TextAlign_Bottom_Left = 6,
TextAlign_Bottom_Center = 7,
TextAlign_Bottom_Right = 8
}; explicit ColorButton(QWidget *parent = 0); protected:
void mousePressEvent(QMouseEvent *); protected:
bool eventFilter(QObject *watched, QEvent *event);
void paintEvent(QPaintEvent *);
void drawBg(QPainter *painter);
void drawText(QPainter *painter); private:
int borderRadius; //圆角半径
int borderWidth; //边框宽度
QColor borderColor; //边框颜色 bool showSuperText; //显示角标
QString superText; //角标文字
QFont superTextFont; //角标文字字体
TextAlign superTextAlign; //角标文字对齐方式
QColor superTextColor; //角标文字颜色 QString text; //文字
QFont textFont; //文字字体
TextAlign textAlign; //文字对齐方式
QColor textColor; //文字颜色 QColor normalColor; //正常颜色
QColor pressedColor; //按下颜色 bool canMove; //是否能移动
QPixmap bgImage; //背景图片
ColorMode colorMode; //背景色模式 bool isPressed; //是否按下 public:
int getBorderRadius() const;
int getBorderWidth() const;
QColor getBorderColor() const; bool getShowSuperText() const;
QString getSuperText() const;
QFont getSuperTextFont() const;
TextAlign getSuperTextAlign()const;
QColor getSuperTextColor() const; QString getText() const;
QFont getTextFont() const;
TextAlign getTextAlign() const;
QColor getTextColor() const; QColor getNormalColor() const;
QColor getPressedColor() const; bool getCanMove() const;
QPixmap getBgImage() const;
ColorMode getColorMode() const; QSize sizeHint() const;
QSize minimumSizeHint() const; public Q_SLOTS:
//设置边框圆角角度
void setBorderRadius(int borderRadius);
//设置边框宽度
void setBorderWidth(int borderWidth);
//设置边框颜色
void setBorderColor(const QColor &borderColor); //设置是否显示角标
void setShowSuperText(bool showSuperText);
//设置角标文字
void setSuperText(const QString &superText);
//设置角标文字字体
void setSuperTextFont(const QFont &superTextFont);
//设置角标文字对齐方式
void setSuperTextAlign(const TextAlign &superTextAlign);
//设置角标文字颜色
void setSuperTextColor(const QColor &superTextColor); //设置文字
void setText(const QString &text);
//设置文字字体
void setTextFont(const QFont &textFont);
//设置文字对齐方式
void setTextAlign(const TextAlign &textAlign);
//设置文字颜色
void setTextColor(const QColor &textColor); //设置正常颜色
void setNormalColor(const QColor &normalColor);
//设置按下颜色
void setPressedColor(const QColor &pressedColor); //设置是否可以移动
void setCanMove(bool canMove);
//设置背景图片
void setBgImage(const QPixmap &bgImage);
//设置颜色模式
void setColorMode(const ColorMode &colorMode); Q_SIGNALS:
void clicked();
}; #endif // WKBUTTON_H

五、核心代码

bool ColorButton::eventFilter(QObject *watched, QEvent *event)
{
if (!isEnabled()) {
return QWidget::eventFilter(watched, event);
} static QPoint lastPoint; if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *e = static_cast<QMouseEvent *>(event);
if (this->rect().contains(e->pos()) && (e->button() == Qt::LeftButton)) {
lastPoint = e->pos();
isPressed = true;
update();
}
} else if (event->type() == QEvent::MouseMove && isPressed && canMove) {
QMouseEvent *e = static_cast<QMouseEvent *>(event);
int dx = e->pos().x() - lastPoint.x();
int dy = e->pos().y() - lastPoint.y();
this->move(this->x() + dx, this->y() + dy);
return true;
} else if (event->type() == QEvent::MouseButtonRelease && isPressed) {
isPressed = false;
update();
} return QWidget::eventFilter(watched, event);
} void ColorButton::paintEvent(QPaintEvent *)
{
//绘制准备工作,启用反锯齿
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); //绘制背景
drawBg(&painter);
//绘制文字
drawText(&painter);
} void ColorButton::drawBg(QPainter *painter)
{
painter->save(); //设置边框颜色及宽度
QPen pen;
pen.setColor(borderColor);
pen.setWidthF(borderWidth);
painter->setPen(pen); //绘制区域要减去边框宽度
QRect rect;
rect.setX(borderWidth);
rect.setY(borderWidth);
rect.setWidth(width() - borderWidth * 2);
rect.setHeight(height() - borderWidth * 2); //如果背景图片存在则显示背景图片,否则显示背景色
if (!bgImage.isNull()) {
//等比例缩放绘制
QPixmap img = bgImage.scaled(rect.width(), rect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
painter->drawPixmap((this->rect().width() - img.width()) / 2, (this->rect().height() - img.height()) / 2, img);
} else {
if (colorMode == ColorMode_Normal) {
if (isPressed) {
painter->setBrush(QBrush(pressedColor));
} else {
painter->setBrush(QBrush(normalColor));
}
} else if (colorMode == ColorMode_Replace) {
QLinearGradient gradient(QPoint(0, 0), QPoint(0, height())); if (isPressed) {
gradient.setColorAt(0.0, pressedColor);
gradient.setColorAt(0.49, pressedColor);
gradient.setColorAt(0.50, normalColor);
gradient.setColorAt(1.0, normalColor);
} else {
gradient.setColorAt(0.0, normalColor);
gradient.setColorAt(0.49, normalColor);
gradient.setColorAt(0.50, pressedColor);
gradient.setColorAt(1.0, pressedColor);
} painter->setBrush(gradient);
} else if (colorMode == ColorMode_Shade) {
QLinearGradient gradient(QPoint(0, 0), QPoint(0, height())); if (isPressed) {
gradient.setColorAt(0.0, pressedColor);
gradient.setColorAt(1.0, normalColor);
} else {
gradient.setColorAt(0.0, normalColor);
gradient.setColorAt(1.0, pressedColor);
} painter->setBrush(gradient);
} painter->drawRoundedRect(rect, borderRadius, borderRadius);
} painter->restore();
} void ColorButton::drawText(QPainter *painter)
{
if (!bgImage.isNull()) {
return;
} painter->save(); //如果要显示角标,则重新计算显示文字的区域
if (showSuperText) {
int offset = 3;
QRect rect;
rect.setX(borderWidth * offset);
rect.setY(borderWidth);
rect.setWidth(width() - borderWidth * offset * 2);
rect.setHeight(height() - borderWidth * 2); Qt::Alignment alignment = Qt::AlignCenter;
if (superTextAlign == TextAlign_Top_Left) {
alignment = Qt::AlignTop | Qt::AlignLeft;
} else if (superTextAlign == TextAlign_Top_Center) {
alignment = Qt::AlignTop | Qt::AlignHCenter;
} else if (superTextAlign == TextAlign_Top_Right) {
alignment = Qt::AlignTop | Qt::AlignRight;
} else if (superTextAlign == TextAlign_Center_Left) {
alignment = Qt::AlignLeft | Qt::AlignVCenter;
} else if (superTextAlign == TextAlign_Center_Center) {
alignment = Qt::AlignHCenter | Qt::AlignVCenter;
} else if (superTextAlign == TextAlign_Center_Right) {
alignment = Qt::AlignRight | Qt::AlignVCenter;
} else if (superTextAlign == TextAlign_Bottom_Left) {
alignment = Qt::AlignBottom | Qt::AlignLeft;
} else if (superTextAlign == TextAlign_Bottom_Center) {
alignment = Qt::AlignBottom | Qt::AlignHCenter;
} else if (superTextAlign == TextAlign_Bottom_Right) {
alignment = Qt::AlignBottom | Qt::AlignRight;
} //绘制角标
painter->setPen(superTextColor);
painter->setFont(superTextFont);
painter->drawText(rect, alignment, superText);
} int offset = 5;
QRect rect;
rect.setX(borderWidth * offset);
rect.setY(borderWidth);
rect.setWidth(width() - borderWidth * offset * 2);
rect.setHeight(height() - borderWidth * 2); Qt::Alignment alignment = Qt::AlignCenter;
if (textAlign == TextAlign_Top_Left) {
alignment = Qt::AlignTop | Qt::AlignLeft;
} else if (textAlign == TextAlign_Top_Center) {
alignment = Qt::AlignTop | Qt::AlignHCenter;
} else if (textAlign == TextAlign_Top_Right) {
alignment = Qt::AlignTop | Qt::AlignRight;
} else if (textAlign == TextAlign_Center_Left) {
alignment = Qt::AlignLeft | Qt::AlignVCenter;
} else if (textAlign == TextAlign_Center_Center) {
alignment = Qt::AlignHCenter | Qt::AlignVCenter;
} else if (textAlign == TextAlign_Center_Right) {
alignment = Qt::AlignRight | Qt::AlignVCenter;
} else if (textAlign == TextAlign_Bottom_Left) {
alignment = Qt::AlignBottom | Qt::AlignLeft;
} else if (textAlign == TextAlign_Bottom_Center) {
alignment = Qt::AlignBottom | Qt::AlignHCenter;
} else if (textAlign == TextAlign_Bottom_Right) {
alignment = Qt::AlignBottom | Qt::AlignRight;
} painter->setPen(textColor);
painter->setFont(textFont);
painter->drawText(rect, alignment, text); painter->restore();
}

六、控件介绍

  1. 超过149个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
  2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
  3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何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动态库文件,可以直接集成到qtcreator中拖曳设计使用。
  14. 目前已经有qml版本,后期会考虑出pyqt版本,如果用户需求量很大的话。

七、SDK下载

  • SDK下载链接:https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取码:877p
  • 下载链接中包含了各个版本的动态库文件,所有控件的头文件,使用demo,自定义控件+属性设计器。
  • 自定义控件插件开放动态库dll使用(永久免费),无任何后门和限制,请放心使用。
  • 目前已提供26个版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
  • 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
  • widget版本(QQ:517216493)qml版本(QQ:373955953)三峰驼(QQ:278969898)。
  • 涛哥的知乎专栏 Qt进阶之路 https://zhuanlan.zhihu.com/TaoQt
  • 欢迎关注微信公众号【高效程序员】,C++/Python、学习方法、写作技巧、热门技术、职场发展等内容,干货多多,福利多多!

最新文章

  1. UIScrollView的封装
  2. Angular2对待一个URL的处理流程
  3. 渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(5)
  4. LA 3523 圆桌骑士
  5. 每天进步一点达——MySQL——myisampack
  6. 第十一届GPCT杯大学生程序设计大赛完美闭幕
  7. Websocket实例
  8. maven多模块项目聚合
  9. PostgreSql的Explain命令详解
  10. [LOJ3086][GXOI/GZOI2019]逼死强迫症——递推+矩阵乘法
  11. mac Robotframework执行时报错Robot Framework installation not found.
  12. git 删除与撤回
  13. a*寻路分析
  14. js打开新页面的方式:
  15. 设计一个BCD码计数器。
  16. MongoDB作为Windows服务来安装 错误1053:服务没有及时响应启动或控制请求
  17. jquery multi-select 实例demo
  18. Apache性能优化总结
  19. POJ 2441 Arrange the Bulls 状压dp
  20. ISO 7816-4: Interindustry Commands for Interchange

热门文章

  1. python链接sql server 乱码问题
  2. FreeRTOS编程风格
  3. Jupyter notebook部署引导
  4. jade总结
  5. nomn文件分析
  6. HDU 6741 树上删叶子节点博弈
  7. SQL SERVER 2008 数据库隔离级别代码演示
  8. go html 转字符串存mysql表中
  9. Task异步
  10. luogu 4768