QStyle(3):PixMetric和SubElement枚举
本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)
本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg
若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。
QStyle::PixMetric枚举及相关成员函数如下
virtual int QStyle::pixelMetric(PixelMetric metric, const QStyleOption *option = Q_NULLPTR, const QWidget *widget = Q_NULLPTR) const = 0; //纯虚函数
返回metric所关联的像素度量值,QStyle::PixMetric枚举见表13-12(完整取值请查阅帮助文档),
此枚举描述了各种像素度量(即与样式相关的大小),与函数pixelMetric()有关
示例13.7:自行绘制复选按钮(重新实现pixelMetric()和subElementRect()函数)
本示例比较综合,演示了怎样绘制如图13-9所示的复选按钮,并且演示了怎样重新实现pixelMetric()和subElementRect()函数,以及QStyle::PixelMetric枚举(PM_XXX)和QStyle::SubElement枚举(SE_XXX)的使用
图13-10为本示例各区域和各枚举代表的意义。注意:Qt内部实现的枚举所代表的意义与本示例可能会有一些不相同。
下面为示例代码
//m.h文件的内容
#ifndef M_H
#define M_H
#include<QtWidgets>
class B:public QProxyStyle{ Q_OBJECT
public:B(){}
//1、重新实现pixelMetric()函数,以自定义复选区域的宽度和高度
int pixelMetric(PixelMetric m, const QStyleOption *op=Q_NULLPTR,
const QWidget *w = Q_NULLPTR) const {
//qDebug()<<m; //输出m的值,读者可以查看到复选框(本示例)使用了哪些PM_开头的枚举
switch(m){
//注意:复选区域的高度和宽度还受到resize()函数设置的复选框大小的影响,比如当resize()
//设置的高度小于此函数返回的高度时,则复选区域的高度为resize()函数的高度,为保持与
//resize()设置的高度一致,可使用QStyleOptionButton::rect成员变量的高度值
//①、设置复选框复选区域的高度和宽度
case PM_IndicatorHeight:return 54;
case PM_IndicatorWidth:return 55;
//②、复选框复选区域与文标签之间的间距
case PM_CheckBoxLabelSpacing:return 88;
//③、其他距离使用父类的实现
default:return QProxyStyle::pixelMetric(m,op,w);} }
//2、重新实现subElementRect()函数,以自定义复选按钮各区域的尺寸
QRect subElementRect(SubElement e, const QStyleOption *op,
const QWidget *w = Q_NULLPTR) const {
//qDebug()<<e; //可输出e以查看其值
const QStyleOptionButton *pb=qstyleoption_cast<const QStyleOptionButton*>(op);
QRect r1;
//①、计算整个复选框的大小
if(pb!=0) r1=pb->rect;
//②、计算SE_CheckBoxIndicator(复选区域),其宽度和高度使用pixelMetric()函数设置的值,
//为使复选区域位于右侧,该矩形区域从复选按钮的右上角坐标计算(这样更便于计算),
//其宽度使用负值(即向左侧绘制矩形)。
QRect r(r1.topRight().x(),0,-pixelMetric(PM_IndicatorWidth,op,w),
pixelMetric(PM_IndicatorHeight,op,w));
//③、计算SE_CheckBoxContents(内容区域和可点击区域)
QRect r2(0,0,r1.width()+r.width(),r.height());
//④、计算SE_CheckBoxFocusRect(焦点区域),焦点区域的高度为设置的字体的高度。
QRect r3(0,0+(r2.height()-w->font().pointSize())/2,r2.width()-1,w->font().pointSize());
//⑤、返回计算出来的各区域的矩形(比较简单)
switch(e){
case QStyle::SE_CheckBoxIndicator:{return r;} //复选区域
case QStyle::SE_CheckBoxContents:{ return r2; } //内容区域
case QStyle::SE_CheckBoxFocusRect:{return r3;} //焦点区域
case QStyle::SE_CheckBoxClickRect:{return r2;} //可点击区域
default: {return QProxyStyle::subElementRect(e,op,w);}} }
//3、重新实现drawControl()函数,以绘制自定义复选按钮的外观
void drawControl(ControlElement e,const QStyleOption *op,
QPainter *pr, const QWidget *w = Q_NULLPTR) const {
qDebug()<<e; //输出e可看到复选框所使用的CE_开头的枚举(控件元素)
qDebug()<<op->state; //还可查看部件的状态
//①、获取复选按钮复选区域的矩形
const QStyleOptionButton *pb=qstyleoption_cast<const QStyleOptionButton*>(op);
QRect r=subElementRect(QStyle::SE_CheckBoxIndicator,op,w);
//②、获取复选按钮除复选区域之外(即复选框的内容区域)的矩形
QRect r2=subElementRect(QStyle::SE_CheckBoxContents,op,w);
//③、获取复选按钮的焦点矩形
QRect r3=subElementRect(QStyle::SE_CheckBoxFocusRect,op,w);
//④、绘制复选按钮的初始外观
if(e==QStyle::CE_CheckBox){
pr->fillRect(r,QColor(111,1,1)); //使用红色填充复选区域
pr->fillRect(r2,QColor(1,111,1)); //使用绿色填充内容区域
//⑤、绘制按下复选按钮时的外观
if(op->state&QStyle::State_Sunken){ //若复选按钮被按下
pr->fillRect(r,QColor(255,255,255)); //首先使用白色画刷清除之前绘制的背景
QBrush bs(QColor(0,0,0));
pr->setBrush(bs); pr->drawEllipse(r);} //然后使用黑色画刷bs绘制一个椭圆
}
//⑥、绘制复选按钮的焦点方框
if(pb->state&QStyle::State_HasFocus){ //若复选按钮获得了焦点
//使用一个点画笔绘制一个无填充的矩形
QPen pn(Qt::DotLine); pr->setBrush(Qt::NoBrush); pr->setPen(pn); pr->drawRect(r3);}
//⑦、绘制复选按钮的文本(垂直居中于r2),此步骤需最后绘制,否则可能会被绘制的其他图形覆盖。
pr->drawText(r2,Qt::AlignVCenter,pb->text); } };
#endif // M_H
//m.cpp文件的内容
#include "m.h"
int main(int argc, char *argv[]){ QApplication aa(argc,argv);
QWidget w;
QPushButton *pb1=new QPushButton("AAA",&w); pb1->move(22,22);pb1->resize(221,22);
QCheckBox *pc=new QCheckBox("CCC",&w); pc->move(99,55);
QFont f; f.setPointSize(22); pc->setFont(f); //为复选按钮设置字体
pc->setStyle(new B()); //复选按钮使用自定义样式
w.resize(444,333); w.show(); return aa.exec(); }
本文作者:黄邦勇帅(原名:黄勇)