Spec-Zone.ru › Qt 5.9

Синтаксис таблицы стилей

Терминология и синтаксические правила таблиц стилей 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 }

Часть объявления правила — это список property: value пар, заключенных в фигурные скобки ({}) и разделенных точкой с запятой. Например:

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

См. раздел Список свойств ниже для списка свойств, предоставляемых виджетами Qt.

Типы селекторов

Во всех предыдущих примерах использовался самый простой тип селектора — селектор типа. Таблицы стилей Qt поддерживают все селекторы, определенные в CSS2. В таблице ниже суммируются наиболее полезные типы селекторов.

Селектор Пример Описание
Универсальный селектор * Соответствует всем виджетам.
Селектор типа QPushButton Соответствует экземплярам QPushButton и его подклассов.
Селектор свойства QPushButton[flat="false"] Соответствует экземплярам QPushButton, которые не являются плоскими. Вы можете использовать этот селектор для проверки любого свойства Qt, которое поддерживает QVariant::toString() (см. документацию функции toString() для получения подробностей). Кроме того, поддерживается специальное свойство class, для имени класса.

Этот селектор также может быть использован для проверки динамических свойств. Для получения дополнительной информации о настройке с использованием динамических свойств, обратитесь к Настройка с использованием динамических свойств.

Вместо =, вы также можете использовать ~= для проверки, содержит ли свойство Qt типа QStringList заданный QString.

Предупреждение: Если значение свойства Qt изменяется после установки таблицы стилей, может потребоваться принудительное пересчет таблицы стилей. Один из способов достижения этого — сбросить таблицу стилей и установить её снова.

Селектор класса .QPushButton Соответствует экземплярам QPushButton, но не его подклассов.

Это эквивалентно *[class~="QPushButton"].

Селектор ID QPushButton#okButton Соответствует всем экземплярам QPushButton, имя объекта которых okButton.
Селектор потомка QDialog QPushButton Соответствует всем экземплярам QPushButton, являющимся потомками (детьми, внуками и т. д.) QDialog.
Селектор ребёнка QDialog > QPushButton Соответствует всем экземплярам QPushButton, являющимся непосредственными потомками QDialog.

Подконтроли

Для стилизации сложных виджетов необходимо получить доступ к подконтролям виджета, таким как кнопка раскрывающегося списка QComboBox или стрелки вверх и вниз QSpinBox. Селекторы могут содержать подконтроли, что позволяет ограничить применение правила для определенных подконтролей виджета. Например:

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

Приведенное выше правило стилизует кнопку раскрывающегося списка всех QComboBoxов. Хотя синтаксис с двойными двоеточиями (::) напоминает псевдоэлементы CSS3, подконтроли Qt концептуально отличаются от них и имеют другие каскадные семантики.

Подконтроли всегда располагаются относительно другого элемента — элемента-ссылки. Этим элементом-ссылкой может быть сам виджет или другой подконтроль. Например, ::drop-down QComboBox по умолчанию размещается в верхнем правом углу прямоугольника отступа QComboBox. ::drop-down по умолчанию размещается в центре прямоугольника содержимого подконтроли ::drop-down. См. раздел Список стилизуемых виджетов ниже для подконтролей, используемых для стилизации виджета, и их стандартных положений.

Прямоугольник начала можно изменить с помощью свойства subcontrol-origin. Например, если мы хотим разместить раскрывающийся список в прямоугольнике отступа QComboBox вместо стандартного прямоугольника отступа, мы можем указать:

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

Выравнивание раскрывающегося списка внутри прямоугольника отступа меняется с помощью свойства subcontrol-position.

Свойства width и height могут быть использованы для управления размером подконтроля. Обратите внимание, что установка изображения image неявным образом устанавливает размер подконтроля.

Схема относительного позиционирования (position : relative) позволяет сместить положение подконтроля от его начального положения. Например, при нажатии кнопки раскрывающегося списка QComboBox стрелка внутри может быть смещена для получения эффекта «нажатия». Для этого мы можем указать:

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

Схема абсолютного позиционирования (position : absolute) позволяет изменить положение и размер подконтроля относительно базового элемента.

После размещения они обрабатываются так же, как виджеты, и могут быть стилизованы с помощью модели ящика.

См. Список подконтролей ниже для списка поддерживаемых подконтролей и Настройка подконтроля индикатора меню QPushButton для реалистичного примера.

Примечание: В случае со сложными виджетами, такими как QComboBox и QScrollBar, если одно свойство или подконтроль настраивается, все остальные свойства или подконтроли также должны быть настроены.

Псевдосостояния

Селекторы могут содержать псевдосостояния, которые указывают на ограничение применения правила в зависимости от состояния виджета. Псевдосостояния появляются в конце селектора, с двоеточием (:) между ними. Например, следующее правило применяется при наведении курсора на QPushButton:

QPushButton:hover { color: white }

Псевдосостояния могут быть инвертированы с помощью оператора восклицания. Например, следующее правило применяется при отсутствии наведения курсора на QRadioButton:

QRadioButton:!hover { color: red }

Псевдосостояния могут быть объединены, в этом случае предполагается логическое И. Например, следующее правило применяется, когда курсор наведен на отмеченный QCheckBox:

QCheckBox:hover:checked { color: white }

Инвертированные псевдосостояния могут встречаться в цепочках псевдосостояний. Например, следующее правило применяется, когда курсор наведен на QPushButton, который не нажат:

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

При необходимости логическое ИЛИ может быть выражено с помощью оператора запятой:

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

Псевдосостояния могут сочетаться с подконтролями. Например:

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

См. раздел Список псевдосостояний ниже для списка псевдосостояний, предоставляемых виджетами Qt.

Разрешение конфликтов

Конфликты возникают, когда несколько правил стиля задают одни и те же свойства с разными значениями. Рассмотрим следующую таблицу стилей:

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

Оба правила соответствуют экземплярам QPushButton с именем okButton и возникает конфликт для свойства color. Для разрешения этого конфликта необходимо учитывать специфичность селекторов. В приведенном выше примере QPushButton#okButton считается более специфичным, чем 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. Однако для вычислений в таблице стилей все селекторы типа имеют одинаковую специфичность, и правило, которое появляется последним, имеет приоритет. Другими словами, color устанавливается в gray для всех QAbstractButton, включая QPushButton. Если нам действительно нужно, чтобы у QPushButton был красный текст, мы всегда можем изменить порядок правил.

Для определения специфичности правила таблицы стилей 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 Specification для получения подробностей. Имейте в виду, что Qt в настоящее время не реализует !important.

Наследование

В классическом CSS, когда шрифт и цвет элемента не заданы явно, они автоматически наследуются от родителя. По умолчанию при использовании таблиц стилей Qt виджет не автоматически наследует настройки шрифта и цвета от своего родительского виджета.

Например, рассмотрим QPushButton внутри QGroupBox:

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() для всех виджетов QWidgets, на которые направлена таблица стилей. Если это вызвало распространение в C++, то это вызовет распространение в таблице стилей и наоборот.

Виджеты внутри пространств имён C++

Селектор типа может использоваться для стилизации виджетов определённого типа. Например,

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

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

Таблица стилей Qt использует QObject::className() виджета для определения того, когда применять селектор типа. Когда пользовательские виджеты находятся внутри пространств имён, QObject::className() возвращает <пространство имён>::<имя класса>. Это конфликтует с синтаксисом подэлементов. Чтобы решить эту проблему, при использовании селектора типа для виджетов внутри пространств имён, необходимо заменить "::" на "--". Например,

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

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

Установка свойств QObject

Начиная с версии 4.3 и выше, любое настраиваемое свойство Q_PROPERTY можно установить с помощью синтаксиса qproperty-<имя свойства>.

Например,

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

Если свойство ссылается на перечисление, объявленное с помощью Q_ENUMS, вы должны ссылаться на его константы по имени, а не по числовому значению.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/stylesheet-syntax.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API