参考:[Qt]自定义QStyle——实现QProgressBar自定义样式
参考:QStyle Progress Bar 样式设计(十七)
前面已经知道了绘制控件只需要把控件的子元素/子控件绘制出来即可。
一个默认的QProgressBar子元素如下:
QProgressBar只有子元素没有子控件(可以与之交互的是子控件,只能展示不能交互的叫子元素)
设计图:
根据这个设计图,各个子元素的位置:
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文件:
#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文件:
#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);
}
}
效果: