Spec-Zone.ru › Qt 5.15

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

Терминология и синтаксические правила таблицы стилей 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>::<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, вы должны ссылаться на его константы по имени, а не по их числовому значению.

Примечание: Используйте синтаксис qproperty с осторожностью, так как он изменяет виджет, который отрисовывается. Кроме того, синтаксис qproperty оценивается только один раз, когда виджет полируется стилем. Это означает, что любая попытка использовать их в псевдосостояниях, таких как QPushButton:hover, не сработает.

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

Spec-Zone.ru

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