Синтаксис таблиц стилей
Терминология и синтаксические правила таблиц стилей 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 изменяется после того, как таблица стилей была установлена, может потребоваться принудительная перекомпиляция таблицы стилей. Один из способов достижения этого — сбросить таблицу стилей и установить её снова. |
| Селектор класса | .QPushButton |
Соответствует экземплярам 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 за более подробной информацией. Имейте в виду, что Qt в настоящее время не реализует !important.
Наследование
В классическом CSS, когда шрифт и цвет элемента не заданы явно, они автоматически наследуются от родителя. При использовании таблиц стилей Qt виджет не автоматически наследует настройки шрифта и цвета от родительского виджета.
Например, рассмотрим QPushButton внутри QGroupBox:
qApp->setStyleSheet("QGroupBox { color: red; } "); QPushButton не имеет явно заданного цвета. Следовательно, вместо наследования цвета от родительского QGroupBox, он имеет системный цвет. Если мы хотим задать цвет для QGroupBox и его дочерних элементов, мы можем написать:
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }"); В отличие от этого, установка шрифта и распространение с помощью QWidget::setFont() и QWidget::setPalette() распространяется на дочерние виджеты.
Виджеты внутри 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/archives/qt-5.6/stylesheet-syntax.html