Spec-Zone.ru › Qt 6.1

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

Терминология и синтаксические правила таблиц стилей 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.
Селектор ребёнка 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-6.1/stylesheet-syntax.html

Spec-Zone.ru

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