Синтаксис таблицы стилей
Терминология и синтаксические правила таблиц стилей 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) } Приведенное выше правило стилизует кнопку выпадающего списка всех QComboBoxes. Хотя синтаксис с двойным двоеточием (::) напоминает псевдоэлементы 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 Style Sheet использует 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.13/stylesheet-syntax.html