QStyleOption類和QStyle類簡介
QStyleOption類存儲QStyle函數使用的參數。QStyleOption及其子類包含了QStyle函數繪制圖形元素所需的所有信息。 由於性能原因,成員函數很少,並且對成員變量的訪問是直接的(即。,使用。或- >操作符)。這種低級的感覺使結構易於使用,並強調這些只是樣式函數使用的參數。 QStyle函數的調用者通常在堆棧上創建QStyleOption對象。結合Qt對QString、QPalette和QColor等類型的隱式共享的廣泛使用,可以確保沒有不必要的內存分配。 |
QStyle類是一個抽象基類,它封裝GUI的外觀和感覺。 Qt包含一組QStyle子類,它們模擬Qt支持的不同平台的樣式(QWindowsStyle、QMacStyle等)。默認情況下,這些樣式構建在Qt GUI模塊中。樣式也可以作為插件提供。 Qt的內置小部件使用QStyle來執行幾乎所有的繪圖,確保它們看起來與等效的本地小部件完全相同。 |
QStyle類
設置風格:
可以使用QApplication::setStyle(QStyle *style)函數設置整個應用程序的樣式。它也可以由應用程序的用戶指定,使用樣式命令行選項: 。
./myapplication -style windows
如果沒有指定樣式,Qt將為用戶的平台或桌面環境選擇最合適的樣式。還可以使用QWidget::setStyle(QStyle *style)函數在單個小部件上設置樣式。
QStyle類的簡要:
如果您正在開發自定義小部件,並希望它們在所有平台上看起來都很好,那么可以使用QStyle函數來執行小部件繪圖的部分,例如drawItemText()、drawItemPixmap()、drawPrimitive()、drawControl()和drawComplexControl()。
大多數QStyle繪制函數有四個參數:
1.枚舉值,指定要繪制哪個圖形元素
2.QStyleOption,指定如何和在哪里呈現該元素
3.用於繪制元素的QPainter
4.執行繪圖的QWidget(可選)
QStyle從QStyleOption中獲取呈現圖形元素所需的所有信息。如果樣式需要小部件執行特殊效果(比如macOS上的動畫默認按鈕),則將小部件作為最后一個參數傳遞,但這不是必須的。實際上,通過正確設置QPainter,您可以使用QStyle來繪制任何繪圖設備,而不僅僅是控件。QStyleOption為可以繪制的各種圖形元素類型有不同的子類。例如,PE_FrameFocusRect需要一個QStyleOptionFocusRect參數。為了確保繪圖操作盡可能快,QStyleOption及其子類具有公共數據成員。有關如何使用的詳細信息,請參閱QStyleOption類文檔。
為了方便,Qt提供了QStylePainter類,它結合了QStyle、QPainter和QWidget。這使得下面寫作替換原有的成為可能:
QStylePainter painter(this); ... painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
取代下面代碼
QPainter painter(this); ... style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);
自定義界面:
通過創建自定義樣式,您可以為應用程序創建自定義外觀。創建自定義樣式有兩種方法。在靜態方法中,您要么選擇一個現有的QStyle類,子類化它,並重新實現虛擬函數來提供自定義行為,或者從頭創建一個完整的QStyle類。在動態方法中,您可以在運行時修改系統樣式的行為。下面描述靜態方法。動態方法描述在QProxyStyle中。
靜態方法的第一步是選擇Qt提供的一種樣式,您將從中構建自定義樣式。您對QStyle類的選擇將取決於哪個樣式與您所期望的樣式最相似。您可以使用的最普通的類是QCommonStyle(不是QStyle)。這是因為Qt要求它的樣式是QCommonStyles。
根據您想要更改的基本樣式的哪些部分,您必須重新實現用於繪制接口部分的函數。為了說明這一點,我們將修改QWindowsStyle繪制的旋轉框箭頭的外觀。箭頭是由draw原語()函數繪制的基本元素,因此我們需要重新實現該函數。
我們需要以下類聲明:
class CustomStyle : public QProxyStyle { Q_OBJECT public: CustomStyle(); ~CustomStyle() {} void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const; };
要繪制上下箭頭,QSpinBox使用PE_IndicatorSpinUp和PE_IndicatorSpinDown原始元素。下面介紹如何重新實現draw原語()函數,以便以不同的方式繪制它們:
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); } }
注意:我們不使用小部件參數,除非將其傳遞給QWindowStyle::drawPrimitive()函數。如前所述,關於要繪制什么以及應該如何繪制的信息是由QStyleOption對象指定的,因此不需要詢問小部件。
如果您需要使用小部件參數來獲取其他信息,請小心確保它不是0,並且在使用它之前它是正確的類型。例如:
const QSpinBox *spinBox = qobject_cast<const QSpinBox *>(widget); if (spinBox) { ... }
**在實現自定義樣式時,您不能僅僅因為枚舉值被稱為PE_IndicatorSpinUp或PE_IndicatorSpinDown就認為小部件是一個QSpinBox。
警告:Qt樣式表目前不支持自定義QStyle子類。在將來的某個版本會解決這個問題。
在Qt應用程序中有幾種使用自定義樣式的方法。最簡單的方法是在創建QApplication對象之前將自定義樣式傳遞給QApplication::setStyle()靜態函數:
#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(); }
在項視圖中使用樣式
視圖中的項的繪制是由委托執行的。Qt的默認委托QStyledItemDelegate也用於計算項目的邊界矩形,以及QStyledItemDelegate支持的各種項目數據角色的子元素。查看QStyledItemDelegate類描述,以找出支持哪些數據類型和角色。您可以在模型/視圖編程中閱讀更多關於項目數據角色的內容。
當QStyledItemDelegate繪制項時,它會繪制CE_ItemViewItem,並使用CT_ItemViewItem計算它們的大小。還要注意,它使用SE_ItemViewItemText設置編輯器的大小。在實現自定義項目視圖繪制樣式時,需要檢查QCommonStyle的實現(以及樣式繼承的任何其他子類)。通過這種方式,您可以發現哪些和如何繪制其他樣式元素,然后您可以重新實現應該以不同方式繪制的元素的繪制。
下面使用一個小例子來說明:
switch (element) { case (PE_PanelItemViewItem): { painter->save(); QPoint topLeft = option->rect.topLeft(); QPoint bottomRight = option->rect.topRight(); QLinearGradient backgroundGradient(topLeft, bottomRight); backgroundGradient.setColorAt(0.0, QColor(Qt::yellow).lighter(190)); backgroundGradient.setColorAt(1.0, Qt::white); painter->fillRect(option->rect, QBrush(backgroundGradient)); painter->restore(); break; } default: QProxyStyle::drawPrimitive(element, option, painter, widget); }
原始元素PE_PanelItemViewItem負責繪制項目的背景,它來自QCommonStyle的CE_ItemViewItem實現。
要添加對繪制新數據類型和項數據角色的支持,需要創建一個自定義委托。但是,如果您只需要支持由默認委托實現的數據類型,則自定義樣式不需要附帶的委托。QStyledItemDelegate類描述提供了關於自定義委托的更多信息。項目視圖標題的繪制也由樣式完成,對標題項的大小以及行和列的大小進行控制。
QStyleOption子類:
QStyleOptionButton, QStyleOptionComplex, QStyleOptionDockWidget, QStyleOptionFocusRect, QStyleOptionFrame, QStyleOptionGraphicsItem, QStyleOptionHeader, QStyleOptionMenuItem, QStyleOptionProgressBar, QStyleOptionRubberBand, QStyleOptionTab, QStyleOptionTabBarBase, QStyleOptionTabWidgetFrame, QStyleOptionToolBar, QStyleOptionToolBox, and QStyleOptionViewItem