QStyle 類是一個(gè)抽象基類,它封裝了Qt GUI 的外觀。
Qt 包含一組 QStyle 子類,它們描述了 Qt 在不同系統(tǒng)平臺(tái)的樣式(QWindowsStyle、QMacStyle 等)。默認(rèn)情況下,這些樣式內(nèi)置于 Qt GUI 模塊中。
樣式也可以作為Qt插件提供。
Qt 的內(nèi)置控件使用 QStyle 來執(zhí)行幾乎所有的繪圖,確??雌饋砼c本地控件完全一樣。
整個(gè)Qt應(yīng)用程序的樣式可以使用QApplication::setStyle ()函數(shù)來設(shè)置。
程序的樣式也可以在運(yùn)行應(yīng)用程序的時(shí)候,使用-style命令行參數(shù)指定。
譬如:
./xxx -style windows
如果用戶沒有指定樣式,Qt 將根據(jù)系統(tǒng)選擇最適合用戶平臺(tái)或桌面環(huán)境的樣式。
也可以使用QWidget::setStyle () 函數(shù)在單個(gè)widget類型控件上設(shè)置樣式。
如果您正在開發(fā)自定義的控件,并希望它們?cè)谒衅脚_(tái)上看起來都類似,您可以使用 QStyle 類成員函數(shù)來執(zhí)行部分控件的繪制,例如drawItemText ()、drawItemPixmap ()、drawPrimitive ()、drawControl () 和drawComplexControl ( ).
大多數(shù) QStyle 繪圖函數(shù)有四個(gè)參數(shù):
一個(gè)枚舉值,指定要繪制的圖形元素
指定如何以及在何處呈現(xiàn)該元素的QStyleOption
用于繪制元素的QPainter
執(zhí)行繪圖的 QWidget(可選)
例如,如果你想在你的控件上繪制一個(gè)帶有焦點(diǎn)的矩形,你可以這樣寫:
void MyWidget::paintEvent(QPaintEvent * /* event */) { QPainter painter(this); QStyleOptionFocusRect option; option.initFrom(this); option.backgroundColor = palette().color(QPalette::Background); style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this); }
QStyle 從QStyleOption獲取渲染圖形元素所需的所有信息??丶鳛樽詈笠粋€(gè)參數(shù)傳遞,以防樣式需要它來執(zhí)行特殊效果(例如 macOS 上的動(dòng)畫默認(rèn)按鈕),但這不是強(qiáng)制性的。事實(shí)上,通過正確設(shè)置 QPainter,可以使用 QStyle 在任何繪圖設(shè)備上繪圖,而不僅僅是控件QWidget。譬如QImage,QPixmap,Qpicture,Qopengldevice,Qprinter.
QStyleOption具有各種子類,用于可以繪制的各種類型的圖形元素。例如,PE_FrameFocusRect需要一個(gè)QStyleOptionFocusRect參數(shù)。
為了確保繪圖操作盡可能快,QStyleOption及其子類具有公共數(shù)據(jù)成員。
為了方便起見,Qt 提供了QStylePainter類,它結(jié)合了 QStyle、QPainter和QWidget。
通??梢赃@樣寫:
QStylePainter painter(this); ... painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
以往我們會(huì)這樣寫:
QPainter painter(this); ... style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);
您可以通過創(chuàng)建自定義樣式來為您的應(yīng)用程序創(chuàng)建自定義的外觀。
創(chuàng)建自定義樣式有兩種方法。
在靜態(tài)方法中,要么子類化現(xiàn)有的 QStyle 類,然后重新實(shí)現(xiàn)虛函數(shù),
要么從頭開始創(chuàng)建整個(gè) QStyle 類。
在動(dòng)態(tài)方法中,您可以在運(yùn)行時(shí)修改系統(tǒng)樣式的行為。
下面介紹靜態(tài)方法。QProxyStyle中描述了動(dòng)態(tài)方法。
靜態(tài)方法的第一步是選擇 Qt 提供的一種樣式,您將從中構(gòu)建自定義樣式。
您對(duì) QStyle 類的選擇將取決于哪種樣式最類似于您想要的樣式。
可以用作基礎(chǔ)的最通用的類是QCommonStyle(不是 QStyle)。
這是因?yàn)?Qt 要求它的樣式是QCommonStyle。
根據(jù)您要更改的基本樣式的哪些部分,您必須重新實(shí)現(xiàn)用于繪制這些界面部分的函數(shù)。
為了說明這一點(diǎn),我們將修改 QWindowsStyle 繪制的旋轉(zhuǎn)框箭頭的外觀。
箭頭是由drawPrimitive () 函數(shù)繪制的原始元素,因此我們需要重新實(shí)現(xiàn)該函數(shù)。我們需要下面的類聲明:
class CustomStyle : public QProxyStyle { Q_OBJECT public: CustomStyle(const QWidget *widget); ~CustomStyle() {} void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; };
為了繪制向上和向下箭頭,QSpinBox使用PE_IndicatorSpinUp和PE_IndicatorSpinDown基本元素。
下面介紹如何重新實(shí)現(xiàn)drawPrimitive () 函數(shù)以不同方式繪制它們:
void CustomStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { if (element == PE_IndicatorSpinUp || element == PE_IndicatorSpinDown) { QPolygon points(3); int x = option->rect.x(); int y = option->rect.y(); int w = option->rect.width() / 2; int h = option->rect.height() / 2; x += (option->rect.width() - w) / 2; y += (option->rect.height() - h) / 2; if (element == PE_IndicatorSpinUp) { points[0] = QPoint(x, y + h); points[1] = QPoint(x + w, y + h); points[2] = QPoint(x + w / 2, y); } else { // PE_SpinBoxDown points[0] = QPoint(x, y); points[1] = QPoint(x + w, y); points[2] = QPoint(x + w / 2, y + h); } if (option->state & State_Enabled) { painter->setPen(option->palette.mid().color()); painter->setBrush(option->palette.buttonText()); } else { painter->setPen(option->palette.buttonText().color()); painter->setBrush(option->palette.mid()); } painter->drawPolygon(points); } else { QProxyStyle::drawPrimitive(element, option, painter, widget); } }
注意,這里沒有用到widget參數(shù),只是將其傳遞給 QWindowStyle::drawPrimitive() 函數(shù)。
如果您需要使用該widget參數(shù)來獲取其他信息,請(qǐng)?jiān)谑褂们靶⌒拇_保它不為 0 且類型正確。例如:
const QSpinBox *spinBox = qobject_cast<const QSpinBox *>(widget); if (spinBox) { ... }
實(shí)現(xiàn)自定義樣式時(shí),不能僅僅因?yàn)槊杜e值稱為PE_IndicatorSpinUp或PE_IndicatorSpinDown就假設(shè)控件是QSpinBox。
注意:自定義 QStyle 子類目前不支持 Qt 樣式表。就是說不能再自定義的QStyle子類中使用樣式表。
在 Qt 應(yīng)用程序中有多種使用自定義樣式的方法。
最簡單的方法是在創(chuàng)建QApplication對(duì)象之前將自定義樣式傳遞給QApplication::setStyle () 靜態(tài)函數(shù):
#include <QtWidgets> #include "customstyle.h" int main(int argc, char *argv[]) { QApplication::setStyle(new CustomStyle); QApplication app(argc, argv); QSpinBox spinBox; spinBox.show(); return app.exec(); }
QApplication::setStyle() 函數(shù)可以在任何地方調(diào)用。通常做法是在QApplication構(gòu)造函數(shù)之前調(diào)用。
您可能希望使您的自定義樣式可用于其他應(yīng)用程序,這些應(yīng)用程序可能不是您的,因此您無法重新編譯。
Qt 插件系統(tǒng)使得創(chuàng)建樣式作為插件成為可能。作為插件創(chuàng)建的樣式在運(yùn)行時(shí)由 Qt 本身作為共享對(duì)象加載。
編譯您的樣式插件并將其放入 Qt 的plugins/styles目錄中。
我們現(xiàn)在有了 Qt 可以自動(dòng)加載的可插入樣式。要在現(xiàn)有應(yīng)用程序中使用您的新樣式,只需使用以下參數(shù)啟動(dòng)應(yīng)用程序:
./myapplication -style custom
聯(lián)系客服