Spec-Zone.ru › Qt

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

Терминология и синтаксические правила таблиц стилей 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 за подробными сведениями. Имейте в виду, что 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.2/stylesheet-syntax.html

Spec-Zone.ru

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