QT界面 理解QStyle和QStyleOption以及QStyleFactory


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM