Spec-Zone.ru › Qt 6.0

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

Терминология и синтаксические правила таблиц стилей 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 Style Sheets следуют Спецификации CSS2:

Специфичность селектора вычисляется следующим образом:

  • подсчитать количество атрибутов ID в селекторе (= a)
  • подсчитать количество других атрибутов и псевдоклассов в селекторе (= b)
  • подсчитать количество имен элементов в селекторе (= c)
  • игнорировать псевдоэлементы [например, subcontrols].

Объединение трех чисел 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 Style Sheets, виджет не автоматически наследует настройки шрифта и цвета от родительского виджета.

Например, рассмотрим 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 Style Sheets, будут вести себя так, как будто пользователь вручную вызвал соответствующие методы 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, вы должны ссылаться на его константы по имени, а не по числовому значению.

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

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

Spec-Zone.ru

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