Синтаксис таблицы стилей
Терминология и синтаксические правила таблиц стилей 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() распространяется на дочерние виджеты.
Если вы хотите, чтобы шрифт и палитра распространялись на дочерние виджеты, вы можете установить флаг 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>::<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.12/stylesheet-syntax.html