样式表(02):【纲】The Style Sheet Syntax [官翻]

The Style Sheet Syntax

Qt样式表的术语和语法规则几乎与HTML CSS相同。如果你已经知道CSS,你可以快速浏览这一部分。

样式规则

样式表由一系列样式规则组成。样式规则由选择器和声明组成。选择器指定哪些小部件受规则影响;声明指定应该在小部件上设置哪些属性。例如:

QPushButton { color: red }

在上面的样式规则中,QPushButton是选择器,{ color: red }是声明。该规则指定QPushButton及其子类(例如MyPushButton)应使用红色作为其前景色。

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

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

QPushButton, QLineEdit, QComboBox { color: red }

相当于这三条规则的顺序:

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

样式规则的声明部分是一系列 { 属性:值对 },用大括号括起来,用分号分隔。例如:

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

有关Qt小部件提供的属性列表,请参见下面的属性列表部分。

选择器类型

到目前为止,所有示例都使用了最简单的选择器类型,即类型选择器。Qt样式表支持CSS2中定义的所有选择器。下表总结了最有用的选择器类型。

SelectorExampleExplanation
统一选择器*匹配所有小部件。
类型选择器QPushButton匹配QPushButton其子类的实例。
属性选择器QPushButton[flat=“false”]匹配不平坦的QPushButton实例。
除了’=’,您还可以使用’~='来测试QStringList类型的Qt属性是否包含给定的QString。
警告:如果设置样式表后Qt属性的值发生更改,则可能需要强制重新计算样式表。实现这一点的一种方法是取消设置样式表并再次设置它。
类选择器.QPushButton匹配QPushButton的实例,但不匹配其子类的实例。
这相当于*[class~=“QPushButton”]。
ID 选择器QPushButton#okButton匹配对象名为okButton的所有QPushButton实例。
后代选择器QDialog QPushButton匹配QPushButton的所有实例,这些实例是QDialog的子代(子代、孙代等)。
子类选择器QDialog > QPushButton匹配QPushButton的所有实例,这些实例是QDialog的直接子对象。

子控件

对于复杂小部件的样式,有必要访问小部件的子控件,例如QComboBox的下拉按钮或QSpinBox的上下箭头。选择器可能包含子控件,使得可以将规则的应用限制到特定的小部件子控件。例如:

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

以上规则为所有QComboBox的下拉按钮设置样式。尽管双冒号(::)语法让人想起CSS3伪元素,但Qt子控件在概念上与这些控件不同,并且具有不同的级联语义。

子控件始终相对于另一个元素(参考元素)定位。 该参考元素可以是小部件或另一个子控件。 例如,默认情况下,将QComboBox的::drop-down放置在QComboBox的Padding矩形的右上角。 默认情况下,:: drop-down放置在:: drop-down子控件的Contents矩形的中心。 请参阅下面的可样式化小部件列表,以获取用于设置小部件样式和其默认位置的子控件。

可以使用subcontrol-origin属性更改要使用的原点矩形。例如,如果要将下拉列表放置在QComboBox的边距矩形中,而不是默认的填充矩形中,则可以指定:

 QComboBox {
     margin-right: 20px;
 }
 QComboBox::drop-down {
     subcontrol-origin: margin;
 }

使用subcontrol-position属性可以更改Margin矩形内下拉列表的对齐方式。

width和height属性可用于控制子控件的大小。 请注意,设置图像会隐式设置子控件的大小。

相对定位方案( position : relative)允许子控件的位置偏离其初始位置。 例如,当按下QComboBox的下拉按钮时,我们可能希望将其中的箭头偏移以产生“按下”效果。 为此,我们可以指定:

 QComboBox::down-arrow {
     image: url(down_arrow.png);
 }
 QComboBox::down-arrow:pressed {
     position: relative;
     top: 1px; left: 1px;
 }

绝对定位方案( position : absolute )允许对子控件的位置和大小相对于参考元素进行更改。

一旦定位,它们就被视为小部件,并且可以使用box模型来设置样式。

请参阅下面的子控件列表以获取支持的子控件列表,并自定义 QPushButton 的菜单指示器子控件以获取实际示例。

注意 : 对于 QComboBox 和 QScrollBar 等复杂的小部件,如果自定义了一个属性或子控件,那么所有其他属性或子控件也必须自定义。

伪状态

选择器可以包含表示基于小部件状态限制规则应用的伪状态。伪状态出现在选择器的末尾,中间有冒号( : )。例如,当鼠标悬停在QPushButton上时,将应用以下规则:

QPushButton:hover { color: white }

伪状态可以使用感叹号运算符求反。例如,当鼠标未悬停在QRadioButton上时,将应用以下规则:

QRadioButton:!hover { color: red }

伪状态可以被链接起来,在这种情况下,逻辑AND是隐含的。例如,以下规则适用于将鼠标悬停在选中的QCheckBox上时:

QCheckBox:hover:checked { color: white }

否定伪状态可能出现在伪状态链中。例如,当鼠标悬停在未按下的QPushButton上时,将应用以下规则:

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

如果需要,可以使用逗号运算符表示逻辑 OR :

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

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

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

有关Qt小部件提供的伪状态列表,请参阅下面的伪状态列表一节。

冲突的解决

当多个样式规则使用不同的值指定相同的属性时,会发生冲突。考虑以下样式表:

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

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

类似地,具有伪状态的选择器比不指定伪状态的选择器更具体。因此,以下样式表指定当鼠标悬停在QPushButton上时,QPushButton应具有白色文本,否则为红色文本:

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

这里有一个棘手的问题:

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

在这里,两个选择器都有相同的特殊性,所以如果鼠标悬停在按钮上,而它被启用,第二个规则优先。如果我们希望文本在这种情况下是白色的,我们可以像这样重新排列规则:

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

或者,我们可以使第一条规则更加具体:

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

类似的问题也出现在类型选择器中。考虑以下示例:

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

这两个规则都适用于QPushButton实例(因为QPushButton继承QAbstractButton),并且color属性存在冲突。因为QPushButton继承了QAbstractButton,所以很可能会假设QPushButton比QAbstractButton更具体。但是,对于样式表计算,所有类型选择器都具有相同的特定性,最后出现的规则优先。换句话说,对于所有QAbstractButtons(包括QPushButtons),颜色都设置为灰色。如果我们真的希望QPushButtons有红色文本,我们总是可以重新排序规则。

为了确定规则的特殊性,Qt样式表遵循CSS2规范:

  • 选择器的特异性计算如下:
    • 计算选择器中ID属性的数量(=a)
    • 计算选择器中其他属性和伪类的数量(=b)
    • 计算选择器中元素名称的数目(=c)
    • 忽略伪元素[即,子控件]。

连接三个数字a-b-c(在一个大基数的数字系统中)就可以得到特异性。

一些例子:

 *             {}  /* a=0 b=0 c=0 -> specificity =   0 */
 LI            {}  /* a=0 b=0 c=1 -> specificity =   1 */
 UL LI         {}  /* a=0 b=0 c=2 -> specificity =   2 */
 UL OL+LI      {}  /* a=0 b=0 c=3 -> specificity =   3 */
 H1 + *[REL=up]{}  /* a=0 b=1 c=1 -> specificity =  11 */
 UL OL LI.red  {}  /* a=0 b=1 c=3 -> specificity =  13 */
 LI.red.level  {}  /* a=0 b=2 c=1 -> specificity =  21 */
 #x34y         {}  /* a=1 b=0 c=0 -> specificity = 100 */ 

级联

样式表可以在QApplication、父窗口小部件和子窗口小部件上设置。任意小部件的有效样式表是通过合并小部件的祖先(父、祖父母等)上的样式表集以及QApplication上的任何样式表集获得的。

当发生冲突时,无论冲突规则的特殊性如何,小部件自己的样式表总是优先于任何继承的样式表。同样地,父窗口小部件的样式表比祖辈窗口小部件的样式表更受欢迎,等等。

这样做的一个后果是,在小部件上设置样式规则会自动使其优先于在祖先小部件的样式表或QApplication样式表中指定的其他规则。考虑下面的例子。首先,我们在QApplication上设置一个样式表:

qApp->setStyleSheet("QPushButton { color: white }");

然后我们在QPushButton对象上设置样式表:

myPushButton->setStyleSheet("* { color: blue }");

QPushButton上的样式表强制QPushButton(和任何子小部件)具有蓝色文本,尽管应用程序范围的样式表提供了更具体的规则集。

结果和我们写的是一样的效果

myPushButton->setStyleSheet("color: blue");

除非QPushButton有子级(这不太可能),否则样式表不会对其产生影响。

样式表级联是一个复杂的主题。 有关详细信息,请参阅CSS2规范。 请注意,Qt当前未实现!important。

继承

在经典CSS中,当未明确设置项目的字体和颜色时,它将自动从父项继承。 默认情况下,使用Qt样式表时,小部件不会自动从其父小部件继承其字体和颜色设置。

例如,考虑QGroupBox中的QPushButton:

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

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

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

相反,使用QWidget::setFont() 和QWidget::setPalette() 设置字体和调色板会传播到子窗口小部件。

如果希望将字体和调色板传播到子窗口小部件,则可以设置Qt::AA_UseStyleSheetPropagationInWidgetStyles标志,如下所示:

QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);

启用小部件样式的字体和调色板传播后,通过Qt样式表进行的字体和调色板更改将表现为用户手动调用了所有控件上相应的QWidget::setPalette() 和QWidget::setFont() 方法。 样式表定位的QWidget。 如果这会导致在C ++中传播,那么将导致在样式表中传播,反之亦然。

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; }"); 

设置QObject属性

从4.3及更高版本开始,可以使用qproperty- <属性名称>语法设置任何可设计的Q_PROPERTY。
例如,

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

如果该属性引用用Q_ENUMS声明的枚举,则应按名称(而不是其数值)引用其常量。

注意:请谨慎使用qproperty语法,因为它会修改正在绘制的小部件。 同样,qproperty语法仅计算一次,即用样式修饰小部件时。 这意味着在伪状态(例如QPushButton:hover)中使用它们的任何尝试都将无效。

网上有一本黄勇写Qt的电子书,可以参考,具体qss部分的内容可以参考他的博客:

https://blog.csdn.net/hyongilfmmm/article/details/83142244?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-6.control&dist_request_id=d400709e-f05e-4810-8018-07e4e2a01e1b&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-6.control

演示代码

#include "Widget.h"

void loadQssFile(){
    QFile file("StyleSheet.qss");
    file.open (QFile::ReadWrite | QIODevice::Text );
    qApp->setStyleSheet (file.readAll ());
    file.close ();
}

int main(int argc, char *argv[])
{
    QApplication a(argc,argv);
    QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);
//    loadQssFile();

    QGroupBox w;

    auto layout = new QVBoxLayout(&w);
    layout->addWidget (new QPushButton("QPushButton"));
    layout->addWidget (new QLabel("QPushButton"));

    qApp->setStyleSheet("QGroupBox,QGroupBox * { background : red; } ");
  
    w.show ();
    a.exec ();
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值