QStyle(3):PixMetric和SubElement枚舉
若對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(); }
本文作者:黃邦勇帥(原名:黃勇)