Spec-Zone.ru › Qt 5.12

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

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

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

Spec-Zone.ru

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