编程与调试 C++ -- Qt QSS 代码编写规范

QT 源码剖析之 QSS 样式表

基础知识

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

/* 选择器 */
QPushButton {
    /* 声明 */
    color: red;
    /* 声明 */
    width: 20px;
}

选择器类型

选择器 示例 说明
通用选择器 * 匹配所有部件。
类型选择器 QPushButton 匹配所有 QPushButton 实例和它的所有子类。
属性选择器 QPushButton[flat="false"] 匹配 QPushButton 的属性 flat 为 false 的实例。
类选择器 .QPushButton 匹配所有 QPushButton 实例,但不包含它的子类。
ID 选择器 QPushButton#okButton 匹配所有 QPushButton 中以 okButton 为对象名的实例。
后代选择器 QDialog QPushButton 匹配所有 QPushButton 实例,它们必须是 QDialog 的子孙部件。
孩子选择器 QDialog>QPushButton 匹配所有 QPushButton 实例,它们必须是 QDialog 的直接子部件。

子控件

一些复杂空间具有子控件,如 QComboBox 的下拉按钮,QSpinBox 的上下箭头,可以指定子控件的样式。

QComboBox::drop-dpwn {
    image:url(:img/res/toolBar/start/btn_zoom_nor.png);
}

伪状态

部分部件具有状态,如 hover,pressed 等,选择器可以包含伪状态来限制规则在部件的指定状态上应用。

QPushButton:hover {
    color: blue;
}

QPushButton:pressed {
    color: yellow;
}

Qt 中,控件支持的声明属性,子控件和伪状态,可以在 Qt 的帮助文档中搜索 Qt Style Sheets Reference 关键字了解。

规范建议

目前,项目中的样式表统一写到 styleSheet.qss 中,方便查阅修改。以往的代码可能存在一定的规范问题,建议新入库的样式遵循下列规则。

对所有控件重新命名

对于一些代码不会操作的控件,比如某些 label,Qt Designer 会自动起名,如 label_2、label_3 等,容易与其他窗口中的控件名重复。

若 QSS 编码不规范,可能导致影响到其他窗口的同名控件。若不好起名,可以增加父控件的前缀,如 settingDlgLabel_2、settingDlgLabel_3。

必须使用后代选择器,即指定控件的父控件

若只使用 ID 选择器,是极为危险的行为,全局范围内任何同名的控件都会受到影响,尤其没有修改控件默认命名的情况。

/* 非常危险 */
#label_2 {
    color: red;
}

/* 正确写法 */
SettingDlg #settingDlgLabel_2 {
    color: red;
}

注意,在某些情况下,你使用的是类型选择器 + ID 选择器,并没有使用后代选择器。

/* 类型选择器 + ID 选择器 */
QLabel #settingDlgLabel_2 {
    color: red;
}

/* 正确写法 */
SettingDlg QLabel #settingDlgLabel_2 {
    color: red;
}

谨慎使用逗号分隔

使用逗号对选择器进行分组时,一定要注意重新指定父控件,否则会导致全局的改变。

/* 错误 */
SettingDlg #settingDlgLabel_2, #settingDlgLabel_3 {
    color: red;
}

/* 正确写法 */
SettingDlg #settingDlgLabel_2, SettingDlg #settingDlgLabel_3 {
    color: red;
}

/* 错误 */
SettingDlg QComboBox, QSpinBox {
    color: red;
}

/* 正确写法 */
SettingDlg QComboBox, SettingDlg QSpinBox {
    color: red;
}

格式规范

  • 选择器之间,{ 之前,需要填充空格。
  • 属性的定义必须另起一行。
  • { 不换行。
  • 属性之前用 4 空格 缩进。
  • 参考 Google CSS 规范中的其他条例。
/* 错误:{ 启了新行 */
SettingDlg #settingDlgLabel_2
{
    color: red;
}

/* 错误:{ 前需要空格 */
SettingDlg #settingDlgLabel_2{
    color: red;
}

/* 错误:属性需要新启行 */
SettingDlg  #settingDlgLabel_2 { color: red; }

/* 错误:属性需要缩进 */
SettingDlg #settingDlgLabel_2 {
color: red;
}

/* 正确写法 */
SettingDlg #settingDlgLabel_2 {
    color: red;
}

Stylesheet Performance Hits with Qt

Stylesheet Performance Hits with Qt

qApp->style()->unpolish(this); // "this" is my main window
qApp->style()->polish(this);
this->update();
QWidgetList all = allWidgets();

// unpolish all
for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
    QWidget *w = *it;
    if (!(w->windowType() == Qt::Desktop) &&        // except desktop
        w->testAttribute(Qt::WA_WState_Polished)) { // has been polished
        m_app->style()->unpolish(w);
    }
}
m_app->style()->unpolish(qApp); // 这行可能很重要。

// repolish all
for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
    QWidget *w = *it;
    if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) {
        if (w->style() == m_app->style())
            m_app->style()->polish(w);         // repolish
        else
            w->setStyleSheet(w->styleSheet()); // touch
    }
}

// re event
for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
    QWidget *w = *it;
    if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) {
        QEvent e(QEvent::StyleChange);
        QApplication::sendEvent(w, &e);
        w->update();
    }
}

参考资料快照
参考资料快照

本文短链接:
If you have any questions or feedback, please reach out .