【翻译 + 整理】Qt样式表详解(1):原理

一、概述

1、样式表是文本规范,可以使用QApplication::setStyleShee()在整个应用程序上设置,也可以使用QWidget::setStyleSheet()在特定的小部件(及其子控件)上设置。

2、如果在不同级别上设置了多个样式表,则Qt将从所有已设置的样式表中得出有效样式表。 这称为级联。

例如,以下样式表指定所有QLineEdits应该使用黄色作为背景色,所有QCheckBoxes应该使用红色作为文本色:

  QLineEdit { background: yellow }
  QCheckBox { color: red }

3、样式表比QPalette强大得多。例如,QPalette::Button角色设置为红色,以使QPushButton获得红色按钮。但是,这不能保证适用于所有样式,因为受不同平台的限制,并且(在Windows和macOS上)受本机主题引擎的限制。样式表使您可以执行仅使用QPalette难以执行或无法执行的各种自定义。

4、样式表被应用在当前小部件样式的顶层,这意味着您的应用程序看起来将尽可能本机化。与调色板不同,样式表可提供以下保证:如果将QPushButton的背景色设置为红色,则可以确保在所有平台上,该按钮在所有样式中均具有红色背景。此外,Qt Designer提供了样式表集成,使您可以轻松地查看不同小部件样式的样式表的效果。

5、样式表可用于为您的应用程序提供独特的外观,而不必继承QStyle。

6、当样式表处于活动状态时,由QWidget::style()返回的QStyle是包装器“样式表”样式,而不是特定于平台的样式。包装器样式可确保遵守任何活动样式表,否则会将绘图操作转发到特定于平台的基础样式(例如Windows上的QWindowsVistaStyle)。 

二、样式表语法

Qt样式表的术语和语法规则与HTML CSS几乎相同。

2.1、样式规则

1、样式表由一系列样式规则组成。样式规则由选择器声明组成。

  • 选择器指定受规则影响的窗口小部件
  • 声明指定应在窗口小部件上设置的属性

例如:

  QPushButton { color: red }

在上面的样式规则中,QPushButton是选择器,{color:red}是声明。 

2、Qt样式表通常不区分大小写(即,color,Color,COLOR和cOloR表示相同的属性)。唯一的例外是类名、对象名和Qt属性名,它们区分大小写。 

3、可以为同一声明指定多个选择器,使用逗号(,)分隔选择器。 例如:

  QPushButton, QLineEdit, QComboBox { color: red }

和下面是相同的:

  QPushButton { color: red }
  QLineEdit { color: red }
  QComboBox { color: red }

4、样式规则的声明部分是属性:值列表,用大括号括起来并用分号分隔。 例如: 

  QPushButton { color: red; background-color: white }

2.2、选择器类型

Qt样式表支持CSS2中定义的所有选择器。下面是最常用的选择器类型:

  • 通用选择器(例如:*):匹配所有小部件。
  • 类型选择器(例如:QPushButton):匹配QPushButton及其子类的实例。
  • 属性选择器(例如:QPushButton[flat="false"]):匹配QPushButton类型属性(使用Q_PROPERTY注册的属性)等于给定值的实例。(除了等号还可以使用〜=来测试QStringList类型的Qt属性是否包含给定的QString)如果在设置样式表后Qt属性的值发生更改,那么应该重新设置样式表。
  • 类选择器(例如:.QPushButton):匹配QPushButton的实例,但不匹配其子类。这等效于* [class〜="QPushButton"]。
  • ID选择器(例如:QPushButton#okButton):匹配objectName为"okButton"的所有QPushButton实例。
  • 后代选择器(例如:QWidget QPushButton):只要QPushButton对象是QWidget对象的子孙对象就匹配。
  • 子选择器(例如:QWidget > QPushButton):匹配QWidget直接子对象中的QPushButton对象。

2.3、子控件

1、对于样式复杂的窗口小部件,必须可以访问该窗口小部件的子控件,例如QComboBox的下拉按钮或QSpinBox的向上和向下箭头。 选择器可能包含子控件,这些子控件可以将规则的应用限制到特定的窗口小部件子控件。 例如:

  QComboBox::drop-down { image: url(dropdown.png) }

2、子控件始终相对于另一个元素(参考元素)定位。 该参考元素可以是小部件或另一个子控件。 例如,默认情况下,QComboBox的::drop-down是放置在QComboBox的Padding矩形的右上角的。 

2.4、伪状态

1、选择器可能包含伪状态,这些伪状态表示基于小部件的状态来限制规则的应用。伪状态出现在选择器的末尾,中间有一个冒号(:)。

例如,当鼠标悬停在QPushButton上时,将应用以下规则:

  QPushButton:hover { color: white }

2、可以使用感叹号运算符否定伪状态。 例如,当鼠标没有悬停在QRadioButton上时,将应用以下规则:

  QRadioButton:!hover { color: red }

3、伪状态可以进行逻辑“与”操作。例如,以下规则适用于鼠标悬停在选中的QCheckBox上方的情况: 

  QCheckBox:hover:checked { color: white }

又例如,当鼠标悬停在未按下的QPushButton上时,将应用以下规则:

QPushButton:hover:!pressed { color: blue; }

4、可以使用逗号运算符表示逻辑或:

QCheckBox:hover, QCheckBox:checked { color: white }

 5、伪状态可以与子控件组合出现。 例如:

QComboBox::drop-down:hover { image: url(dropdown_bright.png) }

2.4、冲突处理规则

当多个样式规则使用不同的值指定相同的属性时,就会发生冲突。 例如:

  QPushButton#okButton { color: gray }
  QPushButton { color: red }

1、这两个规则都匹配objectName为okButton的QPushButton实例,并且color属性存在冲突。 要解决此冲突,我们必须考虑选择器的特殊性。 在上面的示例中,QPushButton#okButton被认为比QPushButton更具体,因为它(通常)引用单个对象,而不是类的所有实例。

2、具有伪状态的选择器比未指定伪状态的选择器更具体(这条规则仅适用于伪状态。 因此,以下样式表指定当鼠标悬停在QPushButton上时QPushButton应该具有白色文本,否则为红色文本:

  QPushButton:hover { color: white }
  QPushButton { color: red }

3、多个伪状态的情况:

  QPushButton:hover { color: white }
  QPushButton:enabled { color: red }

这设置的顺序有关,后面的比前面的优先。enabled状态的颜色覆盖了hover状态的颜色。(hover的范围比enabled的范围小)

要想不覆盖把范围小的放在后面就行:

  QPushButton:enabled { color: red }
  QPushButton:hover { color: white }

或者使用“与”逻辑:

  QPushButton:hover:enabled { color: white }
  QPushButton:enabled { color: red }

4、类型选择器的情况:

  QPushButton { color: red }
  QAbstractButton { color: gray }

后设置的更有优先性,所有按钮颜色都被设为gray。

2.5、级联

可以在QApplication,父窗口小部件和子窗口小部件上设置样式表。

当发生冲突时,无论冲突规则的特殊性如何,始终要优先于任何继承的样式表使用窗口小部件自身的样式表。同样,父小部件的样式表比祖父小部件的样式表更受青睐,依此类推。

2.6、继承

默认情况下,使用Qt样式表时,窗口小部件不会自动从其父窗口小部件继承其字体和颜色设置

例如,QGroupBox中的QPushButton:

  qApp->setStyleSheet("QGroupBox { color: red; } ");

QPushButton没有显式的颜色设置。因此,它具有系统颜色,而不是继承其父QGroupBox的颜色。 如果要在QGroupBox及其子级上设置颜色,可以编写:

  qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");

相反,使用QWidget::setFont()和QWidget::setPalette()设置字体和调色板会传播到子窗口小部件(因为默认设置了Qt::AA_UseStyleSheetPropagationInWidgetStyles属性)。

2.7、C ++命名空间中的小部件

类型选择器可用于为特定类型的小部件设置样式。 例如:

  class MyPushButton : public QPushButton {
      // ...
  }

  // ...
  qApp->setStyleSheet("MyPushButton { background: yellow; }");

Qt样式表使用小部件的QObject::className()来确定何时应用类型选择器。 当自定义窗口小部件位于名称空间内时,QObject::className()返回<namespace> :: <classname>。 这与子控件的语法冲突。 为了克服这个问题,当在名称空间中对窗口小部件使用类型选择器时,必须将“::”替换为“-”。 例如:

  namespace ns {
      class MyPushButton : public QPushButton {
          // ...
      }
  }

  // ...
  qApp->setStyleSheet("ns--MyPushButton { background: yellow; }");

2.8、设置QObject属性

可以使用qproperty- <property name>语法设置任何可设计的Q_PROPERTY。例如:

  MyLabel { qproperty-pixmap: url(pixmap.png); }
  MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }
  QPushButton { qproperty-iconSize: 20px 20px; }

如果属性引用使用Q_ENUMS声明的枚举,则应按名称引用其常量,即不引用其数值。

三、使用样式表自定义Qt小部件

3.1、盒子模式

1、使用样式表时,每个小部件都被视为一个具有四个同心矩形的框:边距矩形、边框矩形、填充矩形和内容矩形。

2、边距(margin),边框宽度(border-width)和填充(padding)属性均默认为零。 在这种情况下,所有四个矩形(边距,边框,填充和内容)都完全重合。

3、可以使用background-image属性为小部件指定背景。 默认情况下,仅在边框内的区域绘制背景图像。

4、背景图像无法随窗口小部件的大小缩放。 为了提供与小部件尺寸一起缩放的“外观”或背景,必须使用边框图像border-image属性。 由于border-image属性提供了背景,因此在指定border-image时不需要指定背景图像。 在这种情况下,如果同时指定了两者,则边框图像将覆盖背景图像

5、图像(image)属性可用于在边框图像上绘制图像。指定的图像不会平铺或拉伸,并且当其大小与小部件的大小不匹配时,将使用image-position属性指定其对齐方式。 与背景图像和边框图像不同,可以在image属性中指定SVG,在这种情况下,图像会根据小部件的大小自动缩放

3.2、子控件

1、小部件被视为彼此重叠绘制的子控件的层次结构(树)。 例如QComboBox绘制下拉子控件,然后是向下箭头子控件。 因此,QComboBox呈现如下:

  • 渲染QComboBox {}规则
  • 渲染QComboBox::drop-down{}规则
  • 渲染QComboBox::down-arrow {}规则

2、子控件共享父子关系。 对于QComboBox,down-arrow的父项是下拉子控件(drop-down),而drop-down的父项就是QComboBox本身。子控件通过subcontrol-position(子控件位置)subcontrol-origin属性放置在其父级中。

猜你喜欢

转载自blog.csdn.net/kenfan1647/article/details/115322362