参考:[Qt]自定义QStyle——实现QProgressBar自定义样式
参考:QStyle Progress Bar 样式设计(十七)
前面已经知道了绘制控件只需要把控件的子元素/子控件绘制出来即可。
一个默认的QProgressBar子元素如下:
QProgressBar只有子元素没有子控件(可以与之交互的是子控件,只能展示不能交互的叫子元素)
设计图:
根据这个设计图,各个子元素的位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | QRect myProgressBarStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const { switch (element) { case CE_ProgressBarContents: return widget->rect(); case SE_ProgressBarContents: return widget->rect(); case SE_ProgressBarLabel: { if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { if(pb->orientation == Qt::Vertical) { return QRect(0,widget->height() * 0.4,widget->width(),widget->height() * 0.2); } else { return QRect(widget->width()*0.4,0,widget->width()*0.2,widget->height()); } } } break; default: return QProxyStyle::subElementRect(element,option,widget); } } |
完整代码:
.h文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #ifndef MYPROGRESSBARSTYLE_H #define MYPROGRESSBARSTYLE_H #include <QProxyStyle> class myProgressBarStyle : public QProxyStyle { public: myProgressBarStyle(); protected: void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override; void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override; QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override; }; #endif // MYPROGRESSBARSTYLE_H |
.cpp文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | #include "myprogressbarstyle.h" #include <QPainter> #include <QStyleOption> #include <QDebug> #include <qdrawutil.h> myProgressBarStyle::myProgressBarStyle() { } void myProgressBarStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget)const { switch (element) { case CE_ProgressBar://整个进度条部分,整个绘制QProgressBar的开始 { if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { QStyleOptionProgressBar subopt = *pb; painter->save(); painter->setBrush(QColor(88, 88, 88, 63)); painter->setPen(Qt::transparent); QRect rect = subElementRect(SE_ProgressBarContents,pb,widget); int diameter = 12; int cx = 100 * diameter / rect.width(); int cy = 100 * diameter / rect.height(); painter->drawRoundRect(rect, cx, cy);//绘制圆角矩形 painter->restore(); drawControl(CE_ProgressBarContents, &subopt, painter, widget); if (pb->textVisible) { subopt.rect = subElementRect(SE_ProgressBarLabel, pb, widget); drawControl(CE_ProgressBarLabel, &subopt, painter, widget); } } } break; case CE_ProgressBarContents://进度条内容部分,区别于文本部分,只包含进度区域 { if (const QStyleOptionProgressBarV2 *pb = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { QRect rect = pb->rect; QStyleOptionProgressBarV2 drawPb = *pb; if(pb->orientation == Qt::Horizontal) { drawPb.rect.setWidth((pb->progress * rect.width()) / pb->maximum); } else { drawPb.rect.setHeight((pb->progress * rect.height()) / pb->maximum); } drawPrimitive(PE_IndicatorProgressChunk, &drawPb, painter, widget); } } break; case CE_ProgressBarGroove://这个元素查看Qt源码发现这个部分宽度为固定值1,而且从效果上看是介于内容和文本之间的部分 { if (option->rect.isValid()) qDrawShadePanel(painter, option->rect, option->palette, true, 1, &option->palette.brush(QPalette::Window)); } break; case CE_ProgressBarLabel://进度条文本部分 { if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { QPalette::ColorRole textRole = QPalette::Text; QRect rect = subElementRect(SE_ProgressBarLabel,option,widget); QPalette shadowPalette = pb->palette; shadowPalette.setColor(textRole, QColor("#ffffff")); QString text = "完成度:" + pb->text; proxy()->drawItemText(painter, rect, Qt::AlignCenter | Qt::TextSingleLine, shadowPalette, pb->state & State_Enabled, text, textRole); } } break; default: return QProxyStyle::drawControl(element,option,painter,widget); } } QRect myProgressBarStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const { switch (element) { case CE_ProgressBarContents: return widget->rect(); case SE_ProgressBarContents: return widget->rect(); case SE_ProgressBarLabel: { if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { if(pb->orientation == Qt::Vertical) { return QRect(0,widget->height() * 0.4,widget->width(),widget->height() * 0.2); } else { return QRect(widget->width()*0.4,0,widget->width()*0.2,widget->height()); } } } break; default: return QProxyStyle::subElementRect(element,option,widget); } } void myProgressBarStyle::drawPrimitive(PrimitiveElement which, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { switch (which) { case PE_IndicatorProgressChunk://此元素表示进度覆盖区域的元素,windows样式是一小节一小节设定的 { painter->save(); QLinearGradient linear; linear.setStart(0,0); linear.setFinalStop(widget->width(), widget->height()); linear.setColorAt(0, QColor(255,182,193)); linear.setColorAt(0.5, QColor(100,149,237)); linear.setColorAt(1, QColor(255,222,173)); painter->setPen(Qt::NoPen); painter->setBrush(linear); painter->drawRect(option->rect); painter->restore(); } break; default: QProxyStyle::drawPrimitive(which, option, painter, widget); } } |
效果: