[Предыдущая: Классы виджетов] [Виджеты и компоновки] [Следующая: Таблицы стилей] Реализация стилей и виджетов, поддерживающих стили
|
QCDEStyle | Внешний вид и поведение CDE |
---|---|
QColor | Цвета, основанные на значениях цветовых моделей RGB, HSV или CMYK |
QCommonStyle | Содержит общие настройки внешнего вида и поведения GUI |
QCursor | Указатель мыши произвольной формы |
QDecorationFactory | Создаёт декорации окна в Qt для встраиваемых Linux-систем |
QFont | Устанавливает шрифт, используемый для отрисовки текста |
QFontDatabase | Информация о шрифтах, доступных в основной оконной системе |
QFontInfo | Общая информация о шрифтах |
QGraphicsAnchor | Представляет якорь между двумя элементами в QGraphicsAnchorLayout |
QGraphicsAnchorLayout | Компоновщик, в котором можно скреплять виджеты вместе в графическом представлении |
QMacStyle | Стиль Mac OS X, использующий Apple Appearance Manager |
QMotifStyle | Внешний вид и поведение Motif |
QPalette | Содержит цветовые группы для каждого состояния виджета |
QS60Style | Внешний вид и поведение интерфейса, подобные приложениям на S60 |
QStyle | Абстрактный базовый класс, описывающий внешний вид и поведение GUI |
QStyleFactory | Создает объекты QStyle |
QStyleHintReturn | Предпочтения стиля, возвращающие информацию о дополнительных, по отношению к базовым, типам |
QStyleHintReturnMask | Предпочтения стиля, возвращающие QRegion |
QStyleHintReturnVariant | Предпочтения стиля, возвращающие QVariant |
QStyleOption | Содержит параметры, используемые в функциях QStyle |
QStylePainter | Вспомогательный класс для рисования элементов QStyle внутри виджета |
QWindowsStyle | Внешний вид и поведение интерфейса, подобные Microsoft Windows |
QWindowsVistaStyle | Внешний вид и поведение интерфейса, подобные Microsoft Windows Vista |
QWindowsXPStyle | Внешний вид и поведение интерфейса, подобные Microsoft WindowsXP |
API QStyle содержит отрисовывающие виджеты функции, статические вспомогательные функции (static helper functions) для общих и сложных задач (например, вычисления позиций рукояток ползунка) и функций для разнообразных вычислений, необходимых во время отрисовки (например, для вычисления предпочитаемых размеров виджетов). Стиль также помогает некоторым виджетам размещать свое содержимое. В дополнение, он создает палитру QPalette, содержащую несколько объектов кисти QBrush для отрисовки.
QStyle отрисовывает графические элементы; элемент - это виджет или часть виджета такая, как кромка кнопки, рамка окна или полоса прокрутки. Большинство функций рисования принимают четыре аргумента:
Когда виджет запрашивает у стиля отрисовку элемента, он предоставляет стиль с опцией стиля QStyleOption, который является классом, содержащим необходимую для отрисовки информацию. Благодаря QStyleOption, QStyle может выполнять отрисовку виджетов в любом месте кода без установления связи с виджетом. Это делает возможным использование функций отрисовки QStyle'а на любом устройстве рисования, т.е., вы можете нарисовать выпадающий список на любом виджете, а не только на QComboBox.
Виджет передается в последнем аргументе в том случае, если стиль нуждается в нем для создания специальных эффектов (таких как анимированные кнопки по умолчанию в Mac OS X), но это не обязательно.
В данном разделе мы будем рассматривать элементы стиля, опции стиля и функции QStyle. В заключение, мы опишем использование палитры.
Элементы в представлениях элементов Qt отрисовываются делегатами. Заголовки представлений элементов тем не менее отрисовываются стилем. Делегат Qt по умолчанию, QStyledItemDelegate, отрисовывет свои элементы частично посредством текущего стиля; он отрисовывает индикаторы флажков и вычисляет ограничивающие прямоугольники для элементов, из которых состоит элемент виджета. В данном документе мы опишем только как реализовать подкласс QStyle. Если вы хотите добавить поддержку других типов данных, отличных от поддерживаемых QStyledItemDelegate, то вы должны реализовать пользовательский делегат. Обратите внимание на то, что делегаты должны быть установлены программно для каждого отдельного виджета (т.е., стандартные делегаты не могут быть предоставлены как подключаемые модули).
Элемент стиля - графическая часть графического интерфейса пользователя. Виджет состоит из иерархии (или дерева) элементов стиля. Например, когда стиль получает запрос на отрисовку кнопки (например, из QPushButton), он отрисовывает метку (текст и пиктограмму), кромку кнопки и прямоугольник фокуса. Кромка кнопки, в свою очередь, состоит из рамки вокруг кромки и двух других элементов, которые будут отображаться позднее. Ниже приведена схематичная иллюстрация дерева элементов кнопки. Мы увидим реальное дерево для QPushButton когда перейдем к отдельным виджетам.
Виджеты необязательно отрисовывать запрашивая стиль для отрисовки только одного элемента. Виджеты могут сделать несколько вызовов стиля для отрисовки разных элементов. Примером является QTabWidget, который отрисовывает свои вкладки и фреймы по отдельности.
Имеется три типа элементов: простейшие элементы, управляющие элементы и сложные управляющие элементы. Элементы определены в перечислениях ComplexControl, ControlElement и PrimitiveElement. Значения каждого элемента перечисления имеет префикс для обозначения его типа: CC_ - для сложных элементов, CE_ - для элементов управления и PE_ - для простейших элементов. В следующих трех разделах мы увидим что определяют разные элементы и увидим примеры использующих их виджетов.
Описание класса QStyle содержит список этих элементов и их роли в стилевом оформлении (styling) виджетов. Мы увидим как их использовать когда применим стиль к отдельным виджетам.
Простейшие элементы - это общие и часто используемые несколькими виджетами элементы графического интерфейса пользователя. Примером таких элементов являются фреймы, кромки кнопок и стрелки для окошек счетчиков, полосы прокрутки и выпадающие списки. Простейшие элементы не могут существовать сами по себе: они всегда являются частью более крупных структурных компонентов. Они не принимают участия во взаимодействии с пользователем, но являются пассивными украшениями графического интерфейса пользователя.
Элемент управления выполняет действие или отображает информацию пользователю. Примеры элементов управления - это кнопки, флажки и заголовки секций в табличных и древовидных представлениях. Элементы управления необязательно являются завершенными виджетами как, например, кнопки, но могут быть также частью виджетов, например, вкладки набора вкладок (tab bar) и ползунки полосы прокрутки. Они отличаются от простейших элементов тем, что не являются пассивными, но выполняют функцию по взаимодействию с пользователем. Элементы управления, состоящие из нескольких элементов, часто используют стиль для вычисления ограничивающих прямоугольников элементов. Доступные субэлементы определены в перечислении SubElement. Это перечисление используется только для вычисления ограничивающих прямоугольников, а субэлементы как таковые не являются графическими элементами, способными быть отрисованными, как простейшие, управляющие и сложные элементы.
Сложные элементы управления содержат субэлементы управления (sub controls). Поведение сложных элементов управления по-разному зависит от того, где пользователь воздействовал на них с помощью мыши и какую клавишу нажал. Это зависит от субэлемента управления (или нескольких), над которыми находится мышь или получено нажатие кнопки мыши. Примеры сложных элементов управления - полосы прокрутки и выпадающие списки. С полосой прокрутки вы можете использовать мышь для перемещения ползунка и нажимать на кнопки сдвига на одну строку вверх и вниз. Доступные субэлементы управления определены в перечислении SubControl.
В дополнение к отрисовке, стиль должен предоставить виджетам информацию о том, в каком субэлементе (или нескольких) было нажата кнопка мыши. Например, QScrollBar нуждается в знании того, нажал ли пользователь на ползунок, бороздку (groove) ползунка или одну из кнопок.
Обратите внимание на то, что субэлементы управления - это не то же самое, что управляющие элементы, описываемые в предыдущем разделе. Вы не можете использовать стиль для отрисовки субэлементов управления; стиль будет только вычислять ограничивающий прямоугольник, в котором субэлементы управления должны быть отрисованы. Тем не менее, обычно сложные элементы управления используют элементы управления и простейшие элементы для отрисовки своих субэлементов управления, что часто используется встроенными стилями Qt, а также стилем Java. Например, стиль Java использует PE_IndicatorCheckBox для отрисовки флажка в групповых рамках (которые являются субэлементами управления CC_GroupBox). Некоторые субэлементы управления имеют эквивалентный элемент управления, например, ползунок полосы прокрутки (SC_SCrollBarSlider и CE_ScrollBarSlider).
Как уже упоминалось, элементы стиля и виджеты используют стили для вычисления ограничивающих прямоугольников субэлементов и субэлементов управления, и пиксельные метрики (pixel metrics), которые являются зависящими от стиля размерами экрана в пикселях, для масштабирования во время отрисовки. Доступные прямоугольники и пиксельные метрики в QStyle представляются тремя перечислениями: SubElement, SubControl и PixelMetric. Значения перечислений можно легко идентифицировать, т.к. они начинаются на SE_, SC_ и PM_.
Стиль содержит также набор подсказок для стиля (style hints), которые представляют собой значения из перечисления StyleHint. Все виджеты обладают разной функциональностью и внешним видом в разных стилях. Например, когда пункты меню не помещаются в один столбец в меню на экране, некоторые стили поддерживают прокрутку, в то время как другие отрисовывают более одного столбца для размещения всех пунктов.
Как правило, стиль обладает набором стандартных изображений (таких как предупреждение, вопрос и ошибка) для окон сообщений, файловых диалогов и т.д., предоставляемых в QStyle перечислением StandardPixmap. Его значения представляют стандартные изображения. Виджеты Qt используют их, так что когда вы реализуете пользовательский стиль добавьте изображения, используемые в реализуемом стиле.
Стиль вычисляет интервал между виджетами в компоновках. Существует два способа выполнения этих вычислений стилем. Вы можете установить PM_LayoutHorizontalSpacing и PM_LayoutVerticalSpacing, так делает стиль java (через QCommonStyle). В качестве альтернативы, вы можете реализовать QStyle::layoutSpacing() и QStyle::layoutSpacingImplementation() если необходим больший контроль за частями компоновки. В этих функциях вы можете вычислять интервал, основываясь на типах элементов управления (QSizePolicy::ControlType) для различных политик размеров (QSizePolicy::Policy), а также опции стиля для данного виджета.
Подклассы QStyleOption содержат всю информацию, необходимую для применения стиля к отдельным элементам. Опции стиля создаются - обычно в куче - и заполняются функцией, вызывающей QStyle. В зависимости от того, на чем отрисовывается стиль будем ожидать разные классы опции стиля. Например, элемент QStyle::PE_FrameFocusRect принимает аргумент QStyleOptionFocusRect, и возможно создание пользовательских подкалссов, которые могут использовать пользовательский стиль. Опции стиля хранят общие переменные по причинам эффективности.
Виджеты могут находиться в одном из нескольких состояний, которые определяются перечислением State. Некоторые флаги состояния (state flags) имеют различное значение в зависимости от виджета, но остальные - общие для всех виджетов, подобно State_Disabled. QStyleOption устанавливает общие состояния с помощью QStyleOption::initFrom(); остальные состояния устанавливаются отдельными виджетами.
Весьма заметно, опции стиля содержат палитру и ограничивающие прямоугольники для отрисовки виджетов. Многие виджеты имеют специализированные опции стиля. Например, QPushButton и QCheckBox используют QStyleOptionButton как опцию стиля, которая содержит текст, пиктограмму и размер пиктограммы. Точное содержимое всех опций будет описано, когда мы будем рассматривать отдельные виджеты.
При переопределении функций QStyle, принимающих параметр QStyleOption, часто нужно преобразовать QStyleOption к подклассу (например, QStyleOptionFocusRect). Для того, чтобы гарантировать безопасность этой операции, вы можете использовать qstyleoption_cast() для преобразования типа указателя. Если объект недопустимого типа, qstyleoption_cast() возвращает 0. Например:
const QStyleOptionFocusRect *focusRectOption = qstyleoption_cast<const QStyleOptionFocusRect *>(option); if (focusRectOption) { ... }
Следующий код иллюстрирует, как использовать QStyle для рисования прямоугольника в фокусе для собственного виджета по событию paintEvent():
void MyWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); ... QStyleOptionFocusRect option(1); option.init(this); option.backgroundColor = palette().color(QPalette::Window); style().drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this); }
Следующий пример демонстрирует, как произвести стиль от существующего стиля, чтобы настроить вид собственного графического элемента:
class CustomStyle : public QWindowsStyle
{
Q_OBJECT
public:
CustomStyle()
~CustomStyle() {}
void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const;
};
void CustomStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
if (element == PE_IndicatorSpinUp || element == PE_IndicatorSpinDown) {
QPolygon points(3);
int x = option->rect.x();
int y = option->rect.y();
int w = option->rect.width() / 2;
int h = option->rect.height() / 2;
x += (option->rect.width() - w) / 2;
y += (option->rect.height() - h) / 2;
if (element == PE_IndicatorSpinUp) {
points[0] = QPoint(x, y + h);
points[1] = QPoint(x + w, y + h);
points[2] = QPoint(x + w / 2, y);
} else { // PE_SpinBoxDown
points[0] = QPoint(x, y);
points[1] = QPoint(x + w, y);
points[2] = QPoint(x + w / 2, y + h);
}
if (option->state & State_Enabled) {
painter->setPen(option->palette.mid().color());
painter->setBrush(option->palette.buttonText());
} else {
painter->setPen(option->palette.buttonText().color());
painter->setBrush(option->palette.mid());
}
painter->drawPolygon(points);
} else {
QWindowsStyle::drawPrimitive(element, option, painter, widget);
}
}
Класс QStyle определяет три функции для отрисовки простейших элементов, элементов управления и сложных элементов управления: drawPrimitive(), drawControl() и drawComplexControl(). Функции принимают следующие параметры:
Не все виджеты отправляют указатель на себя. Если опция стиля, посылаемая в функцию, не содержит необходимую вам информацию, проверьте реализацию виджета чтобы посмотреть, отправляет ли он указатель на самого себя.
Класс QStyle также предоставляет вспомогательные функции, которые используются при отрисовке элементов. Функция drawItemText() отрисовывает текст внутри заданного прямоугольника и принимает палитру QPalette в качестве параметра. Функция drawItemPixmap() помогает выровнять растровое изображение (pixmap) внутри заданного ограничивающего прямоугольника.
Другие функции QStyle выполняют различные вычисления для функций отрисовки. Виджеты также используют эти функции для вычисления подсказок размеров (size hints), а также для вычислений ограничивающих прямоугольников, если они отрисовывают несколько элементов стиля самостоятельно. Также как и функции отрисовки элементов вспомогательные функции принимают несколько аргументов.
QStyle также имеет функции polish() и unpolish(). Перед тем, как будут отображены все виджеты отправляются в функцию polish() и в функцию unpolish() - когда они невидимы. Вы также можете использовать эти функции для установки атрибутов виджетов или выполнения другой работы, которая требуется вашему стилю. Например, если необходимо узнать когда мышь нависнет над виджетом, вам необходимо установить атрибут виджета WA_Hover. Тогда флаг состояния State_MouseOver будет установлен в опциях стиля виджета.
QStyle обладает также несколькими статическими вспомогательными функциями, которые выполняют некоторые общие и трудные задачи. Они могут вычислить позицию ползунка из значения ползунка и трансформировать прямоугольники и отрисовать текст с учетом обратных компоновок (reverse layouts); за подробностями обращайтесь к документации класса QStyle.
Обычный подход, когда переопределяются виртуальные функции QStyle, работает на элементах, которые отличаются от суперкласса; для остальных элементов вы можете просто использовать реализацию суперкласса.
Каждый стиль предоставляет цвет - то есть, QBrush - палитру, которая будет использована для отрисовки виджетов. Для разных состояний виджета имеется свой набор цветов (QPalette::ColorGroup): активный (виджеты в окне, которое находится в фокусе клавиатуры), неактивный (виджеты используются для других окон) и отключенный (виджеты, которые отключены). Состояния можно узнать опросив флаги состояния State_Active и State_Enabled. Каждый набор содержит цвет для определенных ролей, задаваемых перечислением QPalette::ColorRole. Роли описывают в каких ситуациях цвета будут использованы (например, для отрисовки фона виджета, текста или кнопок).
Как роли цвета (color roles) используются определяется стилем. Например, если стиль использует градиенты, то для создания градиента можно использовать цвет из палитры и сделать его темнее или светлее с помощью QColor::darker() и QColor::lighter(). В общем, если вам нужна кисть, которой нет в палитре, попробуйте получить ее из имеющейся.
QPalette, которая предоставляет палитру, хранит цвета для различных состояний виджетов и ролей цвета. standardPalette() возвращает палитру для стиля. Стандартная палитра не устанавливается автоматически когда новый стиль устанавливается на приложение (QApplication::setStyle()) или виджет (QWidget::setStyle()), так что вы должны установить палитру самостоятельно с помощью (QApplication::setPalette()) или (QWidget::setPalette()).
Не рекомендуется жестко кодировать цвета, поскольку приложения и отдельные виджеты могут устанавливать собственные палитры и использовать палитры стилей для отрисовки. Обратите внимание на то, что ни один виджет Qt не устанавливает свою собственную палитру. Стиль java жестко кодирует некоторые цвета, но автор его внешнего вида оставил это в забвении. Конечно, это не значит что стиль будет выглядеть хорошо с любой палитрой.
При реализации стилей имеется несколько проблем, требующих рассмотрения. Здесь мы дадим несколько намеков и совет по реализации.
При реализации стилей необходимо просмотреть код виджетов и код базового класса и его предков. Это связано с тем, что виджеты используют стиль по-разному, поскольку реализация виртуальных функций в разных стилях может оказывать влияние на состояние отрисовки (например, изменение состояния QPainter без восстановления исходного состояния и отрисовка некоторых элементов без использования подходящих пиксельных метрик и субэлементов).
Рекомендуется, чтобы стили не меняли предлагаемый с помощью функции QStyle::sizeFromContents() размер виджетов, но позволяли реализации QCommonStyle обрабатывать его. Если необходимо внести изменения, попытайтесь сделать их минимальными; разработка приложения усложнится, если для разных стилей компоновка виджетов значительно различается.
Мы рекомендуем использовать непосредственно QPainter для отрисовки, т.е. не использовать пиксельные карты или изображения. Это облегчит согласование стиля с палитрой (хотя вы можете установить собственную таблицу цветов в QImage с помощью setColorTable()).
Разумеется, можно отрисовывать элементы и без использования стиля для отрисовки субэлементов как спроектировано Qt. Это не одобряется, поскольку пользовательские виджеты могут зависеть от корректной реализации этих субэлементов. Критический разбор виджетов покажет как Qt использует субэлементы.
Мы реализовали стиль, имеющий сходство с внешним видом и поведением по умолчанию стиля Java (известный до этого как Metal). Мы сделали это, так как это было сравнительно просто реализовать и мы хотели создать стиль для данного обзорного документа. Для сохранения его простым и негромоздким, мы кое-что упростили в стиле, но с Qt безусловно отлично можно сделать точную копию стиля. Однако, конкретных планов по реализации стиля как части Qt нет.
В данном разделе мы рассмотрим некоторые проблемы реализации. В заключение, мы рассмотрим завершенный пример применения стиля Java к виджету. Мы продолжим использовать стиль java на всем протяжении документа в примерах и изображениях виджетов. Сама по себе реализация немного запутана и не предназначена для прочтения вами.
Первым шагом при разработке стиля является выбор базового класса. Мы решили создать подкласс от QWindowsStyle. Данный класс реализует большую часть функциональности, необходимой для выполнения действительного рисования. К тому же, стили windows и java разделяют компоновку субэлементов управления для нескольких сложных элементов управления (что значительно уменьшает объем кода).
Стиль реализован в одном классе. Мы сделали так поскольку нашли удобным хранить весь код в одном файле. Кроме того, это выгодно в точки зрения оптимизации, так как мы создаем меньше объектов. Мы также оставим количество функций минимальным, используя переключатели (switches) для идентификации элемента, который отрисовывается функциями. Результатом этого являются большие функции, но так как мы разделили код для каждого элемента по переключателям, читать код будет легко.
Мы не реализовали полностью каждый элемент из стиля Java. Таким образом, мы уменьшили объем и сложность кода. Вообще, стиль планировался как практический пример для данного обзорного документа по стилям, а не как часть Qt.
Не для всех виджетов реализованы все состояния. Это сделано для часто используемых состояний, например, State_Disabled. Каждое состояние, однако, реализовано как минимум для одного виджета.
Мы реализовали отметки (ticks) только ниже ползунка. Плоские кнопки (flat push) также пропущены. Мы не обрабатываем случай, когда строки заголовков и заголовки присоединяемых окон становятся меньше содержимого, а просто отрисовываем субэлементы управления один за другим.
Мы не пытались эмулировать шрифты Java. Java и Qt используют очень разные механизмы шрифтов (font engines), поэтому мы не рассматривали его ценность, поскольку используем стиль лишь в качестве примера в этом обзоре.
Мы жестко запрограммировали цвета (QPalette не использовалась) для линейных градиентов, используемых, например, для кромок кнопок, панелей инструментов и флажков. Так сделано потому, что палитра Java не может синтезировать такие цвета. В любом случае Java не изменяет эти цвета, основанные на цветовой группе виджета или роли (они не зависят от палитры), так что при любых обстоятельствах это не является проблемой.
Это виджеты Qt, к которым применен стиль. Некоторых виджетов нет в Java, например, QToolBox. Другие содержат элементы, которые отсутствуют у виджетов Java. Примером последнего является виджет-дерево JTree из Java, у которого нет заголовка.
Стиль не обрабатывает обратные компоновки (reverse layouts). Мы предполагаем, что направление компоновки (layout direction) - слева на право. QWindowsStyle обрабатывает обратные виджеты (reverse widgets); если мы реализовали обратные компоновки, то необходимо обновить виджеты, у которых мы изменяли положение субэлементов или изменяли выравнивание текста в метках.
В качестве примера, мы рассмотрим конструирование флажков в стиле java. Мы опишем весь процесс и приведем весь код как стиля java, так и связанных с ним классов Qt. В оставшейся части документа мы не будем рассматривать исходный код отдельных виджетов. Надеемся, это даст вам понимание того как нужно разыскивать в коде конкретные детали реализации; большинство виджетов придерживаются структуры, схожей с флажками. Мы отредактировали код QCommonStyle, удалив из него кое-что не относящееся напрямую к конструированию флажков.
Начнем с рассмотрения того, как QCheckBox создает свою опцию стиля, которой для флажков является QStyleOptionButton:
opt.initFrom(q); if (down) opt.state |= QStyle::State_Sunken; if (tristate && noChange) opt.state |= QStyle::State_NoChange; else opt.state |= checked ? QStyle::State_On : QStyle::State_Off; if (q->testAttribute(Qt::WA_Hover) && q->underMouse()) { if (hovering) opt.state |= QStyle::State_MouseOver; else opt.state &= ~QStyle::State_MouseOver; } opt.text = text; opt.icon = icon; opt.iconSize = q->iconSize();
Сначала мы разрешили QStyleOption установить с помощью initFrom() опцию с общей для всех виджетов информацией. Рассмотрим это кратко.
Булевое значение down равно true, если пользователь нажал на квадратик; для флажка это будет верно вне зависимости от того, отмечен квадратик или нет. Состояние State_NoChange устанавливается, когда имеется флажок с тремя состояниями и он частично отмечен. State_On устанавливается, если квадратик отмечен, а State_Off - если не отмечен. State_MouseOver устанавливается, если мышь наведена на флажок и атрибут виджета Qt::WA_Hover установлен - вы устанавливаете это в QStyle::polish(). В дополнение, опция стиля также содержит текст, пиктограмму и размер пиктограммы кнопки.
initFrom() устанавливает опцию стиля с атрибутами, общими для всех виджетов. Приведем ее реализацию:
state = QStyle::State_None; if (widget->isEnabled()) state |= QStyle::State_Enabled; if (widget->hasFocus()) state |= QStyle::State_HasFocus; if (widget->window()->testAttribute(Qt::WA_KeyboardFocusChange)) state |= QStyle::State_KeyboardFocusChange; if (widget->underMouse()) state |= QStyle::State_MouseOver; if (widget->window()->isActiveWindow()) state |= QStyle::State_Active; #ifdef Q_WS_MAC extern bool qt_mac_can_clickThrough(const QWidget *w); //qwidget_mac.cpp if (!(state & QStyle::State_Active) && !qt_mac_can_clickThrough(widget)) state &= ~QStyle::State_Enabled; #endif #ifdef QT_KEYPAD_NAVIGATION if (widget->hasEditFocus()) state |= QStyle::State_HasEditFocus; #endif direction = widget->layoutDirection(); rect = widget->rect(); palette = widget->palette(); fontMetrics = widget->fontMetrics();
State_Enabled установлен, когда виджет активирован. Когда виджет в фокусе - флаг State_HasFocus установлен. Также флаг State_Active установлен, когда виджет является дочерним для активного окна. Флаг State_MouseOver будет установлен только если у виджета установлен флаг окна WA_HoverEnabled. Уведомляем, что дополнительная навигационная клавиатура должна быть задействована в Qt для включения State_HasEditFocus; по умолчанию она не включена.
В дополнение к установке флагов состояния QStyleOption содержит другую информацию о виджете: direction - направление компоновки, rect - ограничивающий прямоугольник виджета (область, в которой он будет отрисовываться), palette - палитра QPalette, которая будет использована при отрисовке виджета, и fontMetrics - метрики шрифта, используемые виджетом.
Мы даем изображение флажка и опции стиля соответствующую ему.
Флажок выше имеет следующие флаги состояния в опции стиля:
Флаг состояния | Установлен |
---|---|
State_Sunken | Да |
State_NoChange | Нет |
State_On | Да |
State_Off | Нет |
State_MouseOver | Да |
State_Enabled | Да |
State_HasFocus | Да |
State_KeyboardFocusChange | Нет |
State_Active | Да |
QCheckBox отрисовывает себя в QWidget::paintEvent() с помощью опции стиля opt и QStylePainter p. Класс QStylePainter - вспомогательный класс для отрисовки элементов стиля. Весьма заметно, что он обертывает методы в QStyle, используемые для рисования. QCheckBox отрисовывает себя как изложено ниже:
QStylePainter p(this); QStyleOptionButton opt = d->getStyleOption(); p.drawControl(QStyle::CE_CheckBox, opt);
QCommonStyle обрабатывает элемент CE_CheckBox. QCheckBox имеет два субэлемента: SE_CheckBoxIndicator (индикатор отметки) и SE_CheckBoxContents (содержимое, используемое для метки флажка). QCommonStyle также реализует ограничивающие прямоугольники этих субэлементов. Посмотрим на код QCommonStyle:
QStyleOptionButton subopt = *btn; subopt.rect = subElementRect(SE_CheckBoxIndicator, btn, widget); drawPrimitive(PE_IndicatorCheckBox, &subopt, p, widget); subopt.rect = subElementRect(SE_CheckBoxContents, btn, widget); drawControl(CE_CheckBoxLabel, &subopt, p, widget); if (btn->state & State_HasFocus) { QStyleOptionFocusRect fropt; fropt.QStyleOption::operator=(*btn); fropt.rect = subElementRect(SE_CheckBoxFocusRect, btn, widget); drawPrimitive(PE_FrameFocusRect, &fropt, p, widget); }
Как можно видеть из этого фрагмента кода, общий стиль получает ограничивающие прямоугольники двух субэлементов CE_CheckBox и затем отрисовывает их. Если флажок в фокусе, то рамка фокуса также отрисовывается.
Стиль java отрисовывает CE_CheckBoxIndicator, пока QCommonStyle обрабатывает CE_CheckboxLabel. Мы рассмотрим все реализации, а начнем с CE_CheckBoxLabel:
const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt); uint alignment = visualAlignment(btn->direction, Qt::AlignLeft | Qt::AlignVCenter); if (!styleHint(SH_UnderlineShortcut, btn, widget)) alignment |= Qt::TextHideMnemonic; QPixmap pix; QRect textRect = btn->rect; if (!btn->icon.isNull()) { pix = btn->icon.pixmap(btn->iconSize, btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled); drawItemPixmap(p, btn->rect, alignment, pix); if (btn->direction == Qt::RightToLeft) textRect.setRight(textRect.right() - btn->iconSize.width() - 4); else textRect.setLeft(textRect.left() + btn->iconSize.width() + 4); } if (!btn->text.isEmpty()){ drawItemText(p, textRect, alignment | Qt::TextShowMnemonic, btn->palette, btn->state & State_Enabled, btn->text, QPalette::WindowText); }
visualAlignment() корректирует выравнивание текста согласно направлению компоновки. Затем отрисовывается пиктограмма, если она есть, и корректируется интервал слева от текста. drawItemText() рисует текст, принимая выравнивание, направление компоновки и мнемонику в учетной записи (account). Для отрисовки текста правильным цветом также используется палитра.
При отрисовке меток часто получается что-то запутанное. К счастью, обычно эта ситуация обрабатывается базовым классом. Стиль Java реализует собственные надписи в кнопках, так как Java - в отличие от Windows - также центрирует содержимое кнопки при наличии в ней пиктограммы. Вы можете изучить эту реализацию, если вам необходим пример переопределения отрисовки метки.
Взглянем на реализацию в стиле java CE_CheckBoxIndicator в drawControl():
case PE_IndicatorCheckBox: { painter->save(); drawButtonBackground(option, painter, true); if (option->state & State_Enabled && option->state & State_MouseOver && !(option->state & State_Sunken)) { painter->setPen(option->palette.color(QPalette::Button)); QRect rect = option->rect.adjusted(1, 1, -2, -2); painter->drawRect(rect); rect = rect.adjusted(1, 1, -1, -1); painter->drawRect(rect); } if (option->state & State_On) { QImage image(":/images/checkboxchecked.png"); painter->drawImage(option->rect.topLeft(), image); } painter->restore(); break;
Сначала мы сохраняем состояние рисовальщика (painter). Это не всегда необходимо, но в данном случае QWindowsStyle нужен рисовальщик в том же состояние, в каком он был когда был вызван PE_IndicatorCheckBox (Конечно, состояние можно также установить с помощью вызовов функций). Затем используем drawButtonBackground() для отрисовки фона индикатора флажка. Это вспомогательная функция, которая отрисовывает фон, а также рамки кнопок и флажков. Мы рассмотрим эту функцию ниже. Затем мы проверим, не наведена ли мышь на флажок. Если да, то мы отрисовываем рамку флажков в стиле java для случая, когда квадратик не нажат, а мышь наведена на него. Вы можете обратить внимание на то, что java не обрабатывает флажки с тремя состояниями, поэтому мы их не реализовали.
Для нашего индикатора мы используем рисунок png. Также мы можем проверить здесь, не отключен ли виджет. Если отключен, тогда мы используем другое изображение с индикатором в неактивных цветах.
void JavaStyle::drawButtonBackground(const QStyleOption *option, QPainter *painter, bool isCheckbox) const { QBrush buttonBrush = option->palette.button(); bool sunken = option->state & State_Sunken; bool disabled = !(option->state & State_Enabled); bool on = option->state & State_On; if (!sunken && !disabled && (!on || isCheckbox)) buttonBrush = gradientBrush(option->rect); painter->fillRect(option->rect, buttonBrush); QRect rect = option->rect.adjusted(0, 0, -1, -1); if (disabled) painter->setPen(option->palette.color(QPalette::Disabled, QPalette::WindowText)); else painter->setPen(option->palette.color(QPalette::Mid)); painter->drawRect(rect); if (sunken && !disabled) { drawSunkenButtonShadow(painter, rect, option->palette.color(QPalette::Mid), option->direction == Qt::RightToLeft); } }
Мы увидели, как к флажкам применяется стиль java начиная от получения виджетом запроса на рисование и до окончания отрисовки стиля. Чтобы детально изучить то, как отрисовывается каждый виджет, вам нужно изучить код по шагам так же как сделали здесь мы. Однако обычно достаточно знать какие элементы стиля отрисовывает виджет. Виджет создает опцию стиля и вызывает стиль один или более раз для отрисовки элементов стиля из которых он состоит. Обычно этого также достаточно, чтобы знать в каких состояниях может быть виджет и остальное содержимое опции стиля, например то, что перечислено в следующем разделе.
В этом разделе мы рассмотрим как применять стиль к большинству виджетов Qt. Будем надеяться, это сэкономит вам немного времени и усилий во время разработки ваших стилей и виджетов. Вы не найдете здесь информации, которую нельзя найти где-нибудь еще (т.е., изучая исходный код или описания связанных со стилем классов).
В качестве примеров мы будем использовать в основном виджеты в стиле java. Стиль java не отрисовывает каждый элемент в деревьях элементов. Это потому, что они невидимы для этих виджетов в стиле java. Кроме того мы должны убедиться в том, что все элементы реализованы способом, согласованным со стилем java, так как они могут понадобиться пользовательским виджетам (хотя это не исключает предоставление реализаций QWindowsStyle).
Нижеперечисленное предоставлено для каждого виджета:
Дерево элементов содержит простейшие элементы, элементы управления и сложные элементы управления стиля. Сделав нисходящий обход дерева элементов, вы получите последовательность, в которой элементы должны быть отрисованы. В узлах мы написали прямоугольники субэлементов, субэлементов управления и пиксельные метрики, которые учитываются во время отрисовки элемента узла.
Наш подход к процессу применения стиля сосредоточен на отрисовке виджетов. Вычисления используемых во время отрисовки прямоугольников субэлементов, субэлементов управления и пиксельных метрик лишь перечислены как содержимое деревьев элементов. Обратите внимание на то, что имеются прямоугольники и пиксельные метрики, которые используются только виджетами. Это оставляет такие вычисления за пределами критического разбора. Например, функции subControlRect() и sizeFromContents() часто вызывают subElementRect() для вычисления своих ограничивающих прямоугольников. Мы также можем нарисовать деревья для них. Однако то, как выполняются эти вычисления полностью возложено на отдельные стили, а они не следуют определенной структуре (Qt не навязывает определенную структуру). Тем не менее, вы должны убедиться, что используете подходящие пиксельные метрики. Для ограничения размера документа мы решили не включать деревья или описания вычислений, выполняемых стилем Java (или любым другим).
При рассмотрении деревьев вас может озадачить использование различных пиксельных метрик, прямоугольников субэлементов и прямоугольников субэлементов управления. Если вы испытываете сомнения после прочтения описаний перечислений QStyle, мы советуем вам изучить реализации QCommonStyle и QWindowsStyle.
Некоторые из выделенных на изображениях ограничивающих прямоугольников виджетов одинаковы. Причины в том, что некоторые элементы отрисовывают фон в то время, как другие отрисовывают рамки и метки. Если сомневаетесь, проверьте описание каждого элемента в QStyle. Также, некоторые элементы относятся к компоновке, т.е., решают где отрисовывать другие элементы.
Некоторые состояния и переменные являются общими для всех виджетов. Они устанавливаются с помощью QStyleOption::initFrom(). Не все элементы используют эту функцию; это виджеты, создающие опции стиля, а для некоторых элементов информация из initFrom() не является необходимой.
Таблица общих состояний:
Состояние | Когда устанавливается состояние |
---|---|
State_Enabled | Устанавливается, если виджет включен (смотрите QWidget::setEnabled()) |
State_Focus | Устанавливается, если виджет в фокусе (смотрите QWidget::hasFocus()) |
State_KeyobordFocusChange | Устанавливается, когда пользователь изменяет фокус с помощью клавиатуры (смотрите Qt::WA_KeyboardFocusChange) |
State_MouseOver | Устанавливается, когда курсор мыши расположен над виджетом |
State_Active | Устанавливается, если виджет является потомком активного окна. |
State_HasEditFocus | Устанавливается, если виджет в фокусе редактирования. |
Другими общими членами для виджетов являются:
Член | Значение |
---|---|
rect | Ограничивающий прямоугольник отрисовываемого элемента. Устанавливается в ограничивающий прямоугольник виджета (QWidget::rect()). |
direction | Направление компоновки; значение из перечисления Qt::LayoutDirection. |
palette | Палитра QPalette, используемая при отрисовке элемента. Устанавливается в палитру виджетов (QWidget::palette()). |
fontMetrics | QFontMetrics используется для отрисовки текста на виджете. |
Сложные опции стиля (классы, наследуемые от QStyleOptionComplex) используются для сложных элементов стиля разделяя две переменных: subControls и activeSubControls. Обе переменных являются объединением по ИЛИ переменных из QStyle::SubControl. Они отображают из каких субэлементов управления состоит сложный элемент управления и какие из этих элементов управления сейчас активны.
Как упоминалось, стиль вычисляет размеры содержимого виджета, из подсказки (size hints) которых виджеты вычисляют свои размеры. Кроме того, сложные элементы управления также используют стиль для проверки над каким субэлементом управления находится мышь.
Без дальнейших задержек мы представляем критический обзор виджетов; каждому виджету отведен свой подраздел.
Ниже показана структура стиля для кнопок. Сделав нисходящий обход дерева, вы получите последовательность в которой элементы должны быть отрисованы.
Компоновка кнопок, с относительными границами элемента, изменяется от стиля к стилю. Из-за чего показывать ее концептуальные изображения становится сложно. Также элементы могут - даже запланированы - иметь одинаковые границы; PE_PushButtonBevel, например, используется в QCommonStyle для отрисовки элементов, которые его содержат: PE_FrameDefaultButton, PE_FrameButtonBevel и PE_PanelButtonCommand, которые все имеют одни и те же границы в обычном и windows стилях. PE_PushButtonBevel также отвечает за отрисовку индикатора меню (QCommonStyle отрисовывает PE_IndicatorArrowDown).
Ниже приведено изображение кнопки в стиле java, на котором показаны ограничивающие прямоугольники элементов. Для ограничивающих прямоугольников на изображении используются разные цвета; другого назначения они не имеют. Это справедливо также для похожих изображений для других виджетов.
Стиль java, так же как и другие реализованные в Qt стили, не использует PE_FrameButtonBevel. Обычно кнопка с PE_DefaultFrame корректирует прямоугольник PE_PanelButtonCommand с помощью PM_ButtonDefaultIndicator. Корректируя прямоугольник rect с помощью PM_DefaultFrameWidth находят CE_PushButtonLabel.
Теперь рассмотрим опцию стиля для кнопок - QStyleOptionButton. Таблица состояний, которые QPushButton может установить на опцию стиля, следующая:
Состояние | Когда устанавливается состояние |
---|---|
State_Sunken | Кнопка вжата или показано вжатое меню |
State_On | Кнопка отмечена |
State_Raised | Кнопка не плоская и не вжата |
Остальные члены QStyleOptionButton:
Член | Значение |
---|---|
Свойства | Флаги перечисления QStyleOptionButton::ButtonFeatures, которые описывают различные свойства кнопки (см. перечисление) |
icon | Пиктограмма QIcon кнопки (если есть) |
iconSize | Размеры QSize пиктограммы. |
text | QString с текстом кнопки |
Структура радиокнопок и флажков одинакова. Покажем структуру, используя элемент QCheckBox и имена пиксельных метрик:
QStyleOptionButton используется как опция стиля и для радиокнопок, и для флажков. Сначала представим таблицу состояний, которые можно установить в опции:
Состояние | Когда устанавливается состояние |
---|---|
State_sunken | Квадратик нажат |
State_NoChange | Квадратик частично отмечен (для флажков с тремя состояниями.) |
State_On | Квадратик отмечен |
State_Off | Квадратик не отмечен |
Таблицу с остальными членами QStyleOptionButtonClass смотрите в Push Buttons.
В Qt QTabBar использует стиль для отрисовки своих вкладок. Вкладки существуют либо в QTabWidget, в котором содержится QTabBar, или как изолированная вкладка. Если панель не является частью виджета со вкладками, она отрисовывается своей основой (base).
QTabBar расположена вне вкладок, поэтому стиль не контролирует размещение панели. Тем не менее, во время размещения своих вкладок панель запрашивает у стиля PM_TabBarTabHSpace и PM_TabBarTabVSpace, которые являются добавочной шириной и высотой к минимальным размерам метки вкладки (пиктограмма и текст) панели вкладок. Стиль может также продолжать воздействовать на размеры вкладки до того как она будет размещена, пока панель вкладок не запросит CT_TabBarTab. Ограничивающий прямоугольник панели выбирается виджетом со вкладками когда она является частью виджета (принимая во внимание CT_TabBarTab).
Панель вкладок несет ответственность за отрисовку кнопок, которые появляются на ней когда все вкладки не помещаются. Их расположение не управляется стилем, но кнопки являются объектами QToolButton и, следовательно, отрисовываются стилем.
Вот структура стиля для QTabWidget и QTabBar:
Пунктирная линия означает, что панель вкладок содержится в QTabWidget, но виджет ее не отрисовывает самостоятельно, что когда QTabBar не является частью виджета со вкладками он отрисовывает только свою базовую линию (base line), и что панель вкладок содержит две инструментальные кнопки, которые прокручивают панель когда все вкладки на ней не помещаются; смотрите их дерево элементов в Инструментальных кнопках. Также обратите внимание на то, что так как кнопки являются дочерними по отношению к панели вкладок, они отрисовываются после отрисовки панели. Ограничивающие прямоугольники вкладок перекрывают основу с помощью PM_TabBarBaseOverlap.
Вот виджет со вкладками в стиле java:
В стиле java (а также в стиле windows), форма и метка панели вкладок имеют те же ограничивающие прямоугольники, что и CE_TabBarTab. Уведомляем, что вкладки перекрываются рамкой виджета со вкладками. Основа панели вкладок (если она отрисовывается) - это область, где вкладки и рамка перекрываются.
Опция стиля для вкладок (QStyleOptionTab) содержит необходимую для отрисовки вкладок информацию. Опция содержит позицию вкладки в панели вкладок, позицию выделенной вкладки, форму вкладки, текст и пиктограмму. Начиная с Qt 4.1 опция будет приводиться к QStyleOptionTabV2, которая также содержит размеры пиктограмм.
Поскольку вкладки в стиле java не перекрываются, мы также представляем картинку виджета со вкладками в стиле windows. Обратите внимание на то, что если вы хотите перекрытия вкладок по горизонтали, то вы можете это получить отрисовывая вкладки в CE_TabBarTabShape; ограничивающие прямоугольники вкладок не будут изменяться панелью вкладок. Вкладки отрисовываются слева направо в северной (north) форме панели вкладок, сверху вниз в восточной (east) форме панели вкладок, и т.д. Выделенная вкладка отрисовывается последней, поэтому ее легче рисовать над другими вкладками (если они больше).
Таблица состояний, в которые можно установить панель вкладок, следующая:
Состояние | Когда устанавливается состояние |
---|---|
State_Sunken | Вкладка нажата мышью. |
State_Selected | Если это текущая вкладка. |
State_HasFocus | Панель вкладок в фокусе и вкладка выбрана. |
Обращаем внимание, что отдельные вкладки могут быть отключены даже если панель вкладок включена. Вкладка включена, если включена панель вкладок.
Вот таблица членов QStyleOptionTabV2:
Член | Значение |
---|---|
cornerWidgets | Это флаги из перечисления CornerWidget, которые показывают имеются ли на панели вкладок виджеты и в каком углу. |
icon | Пиктограмма QIcon вкладки. |
iconSize | Размеры QSize пиктограммы. |
position | Значение перечисления TabPosition, отображающее положение вкладок в панели относительно других вкладок. |
row | содержит, в которой строке расположена вкладка |
selectedPosition | Значение перечисления SelectedPosition, указывающее - смежная выделенная вкладка или нет. |
shape | Значение перечисления QTabBar::Shape указывает - закругленные или трехгранные уголки у вкладки и ориентацию вкладки. |
text | Текст вкладки |
Рамка виджетов со вкладками использует в качестве опции стиля QStyleOptionTabWidgetFrame. Здесь мы перечислим ее члены. Она не имеет других состояний, кроме тех что устанавливаются общими флагами.
Член | Значение |
---|---|
leftCornerWidgetSize | QSize левого угла виджета (если есть). |
rightCornerWidgetSize | QSize правого угла виджета (если есть). |
lineWidth | содержит толщину линии для отрисовки панели. |
midLineWith | в настоящее время это значение всегда равно 0. |
shape | Форма вкладок в панели вкладок. |
tabBarSize | Размер QSize панели вкладок. |
Вот структура стиля для полос прокрутки:
QScrollBar просто создает свою опцию стиля и затем отрисовывает CC_ScrollBar. Некоторые стили рисуют фон добавленной страницы и субстраницы с помощью PE_PanelButtonBevel, а также используют индикаторные стрелки (indicator arrows) для отрисовки стрелок во вложенной и предыдущей строке индикаторов; мы не включили их в дерево поскольку их использование зависят от индивидуального стиля. PM_MaximumDragDistance стиля - максимальное расстояние в пикселях, на которое мышь может переместиться от границ полосы прокрутки и по-прежнему передвигать регулятор.
Вот изображение полосы прокрутки в стиле java:
Вы можете обратить внимание на то, что наша полоса прокрутки немного отличается от такой же в Java, поскольку имеет два индикатора прокрутки на строку вверх (line up indicators). Мы сделали это чтобы показать как вы можете иметь два различных ограничивающих прямоугольника для одного субэлемента управления. Полоса прокрутки - это пример виджета, который полностью реализован в стиле java - ни QWindowsStyle, ни QCommonStyle не использовались при рисовании.
Посмотрим на разные состояния полосы прокрутки, которые можно установить на опцию стиля:
Состояние | Когда устанавливается состояние |
---|---|
State_Horizontal | Горизонтальная полоса прокрутки |
Опцией стиля QScrollBar является QStyleOptionSlider. Его члены перечислены в следующей таблице. Опция используется всеми объектами QAbstractSlider; здесь мы опишем только члены, относящиеся к полосам прокрутки.
Член | Значение |
---|---|
maximum | максимальное значение полосы прокрутки |
minimum | минимальное значение полосы прокрутки |
notchTarget | количество пикселей между отметками |
orientation | значение из перечисления Qt::Orientation, которое указывает, будет ли полоса прокрутки вертикальной или горизонтальной |
pageStep | число, на которое увеличивается или уменьшается значение ползунка (относительно размера ползунка и его диапазона значений) при прокрутке на страницу. |
singleStep | число, на которое увеличивается или уменьшается значение ползунка при прокрутке на один шаг (или строку) |
sliderValue | Значение ползунка |
sliderPosition | позиция регулятора ползунка. Это то же самое, что и sliderValue если полоса прокрутки равна QAbstractSlider::tracking. Если нет, то полоса прокрутки не обновляет свое значение до тех пор, пока регулятор удерживается мышью. |
upsideDown | содержит направление движения полосы прокрутки, при котором ее значение увеличивается. Это используется для всех абстрактных ползунков вместо QStyleOption::direction. |
При вычислении подсказки размера ползунков, из стиля запрашиваются PM_SliderTickness и PM_SliderLength. Как и с полосами прокрутки QSlider позволяет пользователю передвигать только регулятор, если мышь находится в пределах PM_MaximumDragDistance от границ ползунка. При отрисовывании себя ползунок создает опцию стиля и вызывает drawComplexControl() с CC_Slider:
Мы также показываем изображение ползунка в стиле java. Мы покажем ограничивающие прямоугольники субэлементов управления, так как все рисование выполняется в CC_Slider.
QSlider использует QStyleOptionSlider, как поступают все объекты QAbstractSlider. Представляем таблицу членов, оказывающих действие на QSlider:
Член | Значение |
---|---|
maximum | максимальное значение ползунка |
minimum | минимальное значение ползунка |
notchTarget | это количество пикселей между двумя отметками |
orientation | значение перечисления Qt::Orientation, которое указывает будет ли ползунок вертикальным или горизонтальным. |
pageStep | число, на которое увеличится или уменьшится значение ползунка при прокрутке на страницу |
singleStep | число, на которое увеличится или уменьшится значение ползунка при прокрутке на один шаг (или строку). |
sliderValue | значение ползунка. |
sliderPosition | положение ползунка, заданное как значение ползунка. Оно будет равно sliderValue если ползунок равен tracking; если нет, то значение ползунка не будет меняться до тех пор, пока регулятор удерживается мышью. |
upsideDown | этот член используется для всех абстрактных ползунков вместо QStyleOption::direction. |
Вы должны обратить внимание на то, что ползунки не используют направление для обратных компоновок (reverse layouts); они используют upsideDown.
Когда QSpinBox отрисовывает себя, он создает QStyleOptionSpinBox и запрашивает стиль для отрисовки CC_SpinBox. Поле редактирования - однострочный редактор, который является дочерним для окошка счетчика. Размеры поля вычисляются стилем с помощью SC_SpinBoxEditField.
Далее представлено дерево стиля для окошка счетчика. Использование стилем примитива панели кнопки не является необходимым для рисования фона индикатора. На рисунке ниже показано дерево с субэлементами QSpinBox'а в стиле java.
QStyleOptionSpinBox - опция стиля для окошек счетчика. Она может установить окошко счетчика в следующие состояния:
Состояние | Когда устанавливается состояние |
---|---|
State_Sunken | Установлен, если на одном из субэлементов управления CC_SpinUp или CC_SpinDown щелкнули мышью. |
Остальные члены опции стиля окошка счетчика:
Свойство | Функция |
---|---|
frame | Булевое значение, равное true если окошко счетчика отрисовывает рамку. |
buttonSymbols | Значение перечисления ButtonSymbols, предопределяющее символ на кнопках изменения значения (меньше/больше). |
stepEnabled | Значение StepEnabled указывает, какая из кнопок окошка счетчика нажата. |
Сложный элемент управления строки заголовка, CC_TitleBar, используется для отрисовки строки заголовка внутренних окон в QMdiArea. Обычно он состоит из заголовка окна и кнопок закрытия, системного меню, сворачивания и разворачивания окна. Некоторые стили также предоставляют кнопки затенения окна и кнопку контекстно чувствительной помощи.
Строка заголовка отрисовывается в CC_TitleBar без использования субэлементов. Как отрисовывать свои кнопки каждый стиль решает самостоятельно, но имеются стандартные пиксельные карты для кнопок, которые стиль должен предоставить.
На картинке выше строки заголовка в стиле java мы показали ограничивающие прямоугольники субэлементов управления, поддерживаемых стилем java (все они отрисовываются со стандартными пиксельными картами). Обычно для отрисовки фона кнопок используется PE_PanelButtonTool, но это неправильно.
Опцией стиля для строк заголовка является QStyleOptionTitleBar. Ее элементы:
Член | Значение |
---|---|
icon | Пиктограмма строки заголовка |
text | Текст метки строки заголовка |
windowFlags | Флаги перечисления Qt::WindowFlag. Флаги окна используются QMdiArea для управления окном. |
titleBarState | Это QWidget::windowState() окна, содержащего строку заголовка. |
QComboBox использует стиль для отрисовки кнопки и метки нередактируемых комбинированных списков выбора с помощью CC_ComboBox и CE_ComboBoxLabel.
Список, который всплывает, когда пользователь щелкает мышью на выпадающем списке, отрисовывается делегатом, который мы не рассматриваем в данном обзоре. Тем не менее вы можете использовать стиль чтобы управлять размерами и положением выпадающего списка с помощью субэлемента SC_ComboBoxListBoxPopup. Стиль также решает, где для редактируемых комбинированных списков будет поле редактирования с помощью SC_ComboBoxEditField; поле редактирование - QLineEdit, дочерний по отношению к выпадающему списку.
На картинке выше показан выпадающий список в стиле java, мы выделили его субэлементы и прямоугольники субэлементов:
Выпадающие списки в Java не используют прямоугольник фокуса; они изменяют цвет фона, когда получают фокус. SC_ComboBoxEdit field используется QComboBox как для вычисления размеров поля редактирования, так и стилем для вычисления размеров метки выпадающего списка.
Опцией стиля выпадающих списков является QStyleOptionComboBox. Он может быть установлен в следующие состояния:
Состояние | Когда устанавливается |
---|---|
State_Selected | Комбинированный список нередактируемый и получил фокус |
State_Sunken | Активирован SC_ComboBoxArrow |
State_on | Виден контейнер (выпадающий список) комбинированного списка выбора |
Остальные члены опции стиля:
Член | Значение |
---|---|
currentIcon | Пиктограмма текущего (выделенного) элемента выпадающего списка. |
currentText | Текст текущего элемента в комбинированном списке выбора. |
editable | Редактируемый выпадающий список или нет. |
frame | Имеет ли выпадающий список рамку или нет. |
iconSize | Размеры пиктограммы текущего элемента. |
popupRect | Ограничивающий прямоугольник всплывающего списка, принадлежащего выпадающему списку. |
Когда вычисляются подсказки размеров, QGroupBox извлекает из стиля три пиксельных метрики: PM_IndicatorWidth, PM_CheckBoxLabelSpacing и PM_IndicatorHeight. QGroupBox имеет следующее дерево элементов стиля:
Qt не налагает ограничений на то, как флажок будет отрисовываться; стиль java отрисовывает его с помощью CE_IndicatorCheckBox. Полное дерево смотрите в статье Флажки и радиокнопки.
Мы также предоставим изображение виджета с субэлементами управления и нарисованными прямоугольниками субэлементов управления:
Опцией стиля для групповой рамки является QStyleOptionGroupBox. Могут быть установлены следующие состояния:
Состояние | Когда устанавливается |
---|---|
State_On | Флажок отмечен |
State_Sunken | Флажок нажат |
State_Off | Флажок не отмечен (или нет флажка) |
Остальные члены QStyleOptionGroupBox:
Член | Значение |
---|---|
Свойства | флаги перечисления QStyleOptionFrameV2::FrameFeatures описывают рамку групповой рамки. |
lineWidth | Толщина линии, которой отрисовывается панель. Всегда равно 1. |
text | Текст групповой рамки. |
textAlignment | Выравнивание заголовка групповой рамки |
textColor | Цвет QColor текста |
Поскольку структура разделителей проста и не содержит никаких субэлементов, мы не стали включать изображение разделителей. CE_Splitter не использует никаких других элементов или метрик.
Для своей опции стиля разделители используют базовый класс QStyleOption. Она может установить следующие флаги состояния:
Состояние | Когда устанавливается |
---|---|
State_Horizontal | Установлен, если это горизонтальный разделитель |
QSplitter не использует initFrom() для установки своей опции; она самостоятельно устанавливает флаги State_MouseOver и State_Disabled.
Элемент CE_ProgressBar используется классом QProgressBar и он является лишь элементом, используемым данным виджетом. Начнем наш обзор структуры стиля:
Здесь представлен индикатор выполнения в стиле windows (ограничивающие прямоугольники для стиля java такие же):
Опцией стиля для QProgressBar является QStyleOptionProgressBarV2. Индикатор выполнения не устанавливает никаких флагов состояния, но это делают другие члены опции:
Член | Значение |
---|---|
minimum | Минимальное значение индикатора выполнения |
maximum | Максимальное значение индикатора выполнения |
progress | Текущее значение индикатора выполнения |
textAlignment | Какое выравнивание будет у текста в метке |
textVisible | Будет ли отрисована метка |
text | Текст метки |
orientation | Индикатор выполнения может быть вертикальным или горизонтальным |
invertedAppearance | Инвертированное направление (т.е., справа налево в горизонтальном индикаторе) |
bottomToTop | Если это булевое значение равно true, то метка вертикального индикатора выполнения поворачивается на 90 градусов. |
Инструментальные кнопки существуют либо автономно либо как часть панелей инструментов. Отрисовываются они одинаково. QToolButton отрисовывает только один элемент стиля: CC_ToolButton.
Поскольку вам может это понадобиться (во всяком случае, если вы читали данный документ последовательно), мы приведем дерево структуры стиля виджета:
Обратите внимание на то, что PE_FrameButtonTool и PE_IndicatorArrowDown включены в состав дерева, поскольку стиль java отрисовывает их, но если вам нужно, их можно спокойно пропустить. Структура может иметь отличия. QWindowsStyle, например, отрисовывает в CE_ToolButton и PE_IndicatorButtonDropDown, и PE_IndicatorArrowDown.
Мы также приводим изображение инструментальной кнопки, где выделены ограничивающие прямоугольники субэлементов и субэлементы управления.
Вот таблица состояния для инструментальных кнопок:
Состояние | Когда устанавливается |
---|---|
State_AutoRise | У инструментальной кнопки установлена свойство autoRise |
State_raised | Кнопка не вжата (т.е., отмечена или нажата мышью). |
State_Sunken | кнопка вжата |
State_On | кнопку можно отметить и она отмечена. |
QStyleOptionToolButton также содержит следующие члены:
Член | Значение |
---|---|
arrowType | значение перечисления Qt::ArrowType, которое содержит направление стрелки кнопки (если стрелка используется вместо пиктограммы) |
Свойства | флаги перечисления QStyleOptionToolButton::ButtonFeature описывают имеет ли кнопка стрелку, меню и/или задержку появления (popup-delay). |
font | шрифт QFont метки кнопки |
icon | пиктограмма QIcon инструментальной кнопки |
iconSize | размер пиктограммы кнопки |
pos | местоположение кнопки, как задано QWidget::pos() |
text | текст кнопки |
toolButtonStyle | значение перечисления Qt::ToolButtonStyle, которое определяет будет ли на кнопке показана пиктограмма, текст или и то, и другое. |
Панели инструментов являются частью каркаса главного окна и взаимодействует с QMainWindow, которому они принадлежат пока строят свою опцию стиля. В главном окне имеется 4 области где могут быть расположены панели инструментов. Они располагаются по четырем сторонам окна (т.е., северной, южной, западной и восточной). Внутри каждой области может быть более чем одна линейка панелей инструментов; линейка состоит из расположенных рядом панелей инструментов с одинаковой ориентацией (вертикальной или горизонтальной).
Объекты QToolbar в Qt состоят из трех элементов - CE_ToolBar, PE_IndicatorToolBarHandle и PE_IndicatorToolBarSeparator. QMainWindowLayout вычисляет ограничивающие прямоугольники (т.е., расположение и размеры панелей инструментов и их содержимого). Главное окно также использует sizeHint() элементов в панелях инструментов при вычислении размеров панелей.
Вот дерево элементов для QToolBar:
Пунктирные линии указывают, что QToolBar сохраняет экземпляр QToolBarLayout и что объекты QToolBarSeparator сохраняется QToolBarLayout'ом. Когда панель инструментов плавающая (т.е., имеет собственное окно) элемент PE_FrameMenu отрисовывается, в остальных случаях QToolbar отрисовывает CE_ToolBar.
Вот изображение панели инструментов в стиле java:
В качестве опции стиля QToolBarSaparator использует QStyleOption. Она устанавливает флаг State_horizontal если панель инструментов расположена горизонтально. В других случаях используется initFrom().
Опцией стиля для QToolBar является QStyleOptionToolBar. Устанавливается только флаг состояния (помимо общих флагов) State_Horizontal если панель горизонтальная (т.е., в северной или южной области панели инструментов). Переменные-члены опции стиля:
Член | Значение |
---|---|
Свойства | Является ли панель перемещаемой определяется значением в ToolBarFeature, которое может быть равным либо Movable, либо None. |
lineWidth | Ширина линии рамки панели инструментов. |
midLineWidth | В настоящее время переменная не используется и всегда равна 0. |
positionOfLine | Местоположение линейки панели инструментов внутри области панели инструментов, которой она принадлежит. |
positionWithinLine | Местоположение панели инструментов внутри линейки панели инструментов. |
toolBarArea | Область, в которой "живет" панель инструментов. |
Меню в Qt реализованы в классе QMenu. QMenu сохраняет список действий, которые оно отрисовывает как пункты меню. Когда QMenu получает события рисования, оно вычисляет размеры каждого пункта меню и отрисовывает их по одному с помощью CE_MenuItem. (Пункты меню не имеют разделительного элемента для своих меток (содержимого), поэтому все рисование выполняется в CE_MenuItem.) Меню также рисует рамку с помощью PE_FrameMenu. Оно также рисует CE_MenuScroller если стиль поддерживает прокрутку. CE_MenuTearOff отрисовывается если меню слишком велико для своего ограничивающего прямоугольника.
В дерево структуры стиля мы также включили QMenu, поскольку оно также выполняет работу, связанную с созданием стиля. Ограничивающие прямоугольники пунктов меню вычисляются для подсказок размеров меню, а также когда меню отображается или изменяет свои размеры.
Элементы CE_MenuScroller и CE_MenuTearOff обрабатываются QCommonStyle и не отображаются до тех пор, пока меню не станет слишком велико чтобы поместиться на экране. PE_FrameMenu отрисовывается только для всплывающих (pop-up) меню.
QMenu вычисляет прямоугольники, основываясь на их действиях и вызывая CE_MenuItem и CE_MenuScroller, если стиль поддерживает это.
Также часто используется PE_IndicatorCheckBox (вместо использования PE_IndicatorMenuCheckMark) и PE_IndicatorRadioButton для отрисовки пунктов меню, которые можно отмечать; мы не включили их в дерево стиля, поскольку это является необязательным и изменяется от стиля к стилю.
Опцией стиля для элементов меню является QStyleOptionMenuItem. Следующие таблицы описывают ее флаги состояния и другие члены.
Состояние | Когда устанавливается |
---|---|
State_Selected | Мышь находится над действием и действие не является разделителем (separator). |
State_Sunken | Кликнули мышью на пункте меню. |
State_DownArrow | Устанавливается, если элемент меню является скроллером (scroller) меню и разворачивает меню вниз. |
Член | Значение |
---|---|
checkType | Значение из перечисления CheckType, которое равно либо NotCheckable, либо Exclusive, либо NonExclusive. |
checked | Булевое значение, равное true если пункт меню отмечен. |
font | Шрифт QFont для использования в тексте пунктов меню. |
icon | Пиктограмма QIcon пункта меню. |
maxIconWidth | Максимальная ширина, допустимая для пиктограммы |
menuHasChecableItem | Булевое значение, которое равно true если хотя бы один пункт меню может быть отмечен. |
menuItemType | Тип пункта меню. Значение из MenuItemType. |
menuRect | Ограничивающий прямоугольник для QMenu, в котором находятся пункты меню. |
tabWidth | Расстояние между текстом пункта меню и "горячими" клавишами. |
text | Текст пункта меню |
Установка опции стиля для CE_MenuTearOff и CE_MenuScroller также использует QStyleOptionMenuItem; они только устанавливают переменную menuRect в добавок к общим настройкам опции стиля QStyleOption с помощью initFrom().
QMenuBar использует стиль для отрисовки каждого пункта меню и пустой области панели. Выпадающие (pull-down) меню сами являются объектами QMenu (смотрите Меню). Дерево элементов стиля для панели меню следующее:
Панель и пустая область отрисовываются после элементов меню. Рисовальщик QPainter, который QMenuBar отправляет стилю, располагает ограничивающими прямоугольниками вырезанных (clipped out) пунктов меню (т.е., области отсечения), таким образом вам не нужно беспокоиться об отрисовке над пунктами меню. Пиксельные метрики в QMenuBar используются при вычислении ограничивающих прямоугольников пунктов меню.
Для пунктов меню используется QStyleOptionMenuItem. Члены, используемые QMenuBar, описаны в следующей таблице:
Член | Значение |
---|---|
menuRect | ограничивающий прямоугольник всей панели меню, которой принадлежат пункты меню. |
text | текст пункта меню |
icon | пиктограмма пункта меню (пиктограмма отрисовывается не во всех стилях) |
QStyleOptionMenuItem также используется для рисования CE_EmptyMenuBarArea.
QStyleOptionFrame используется для отрисовки рамки панели. lineWidth устанавливается в значение PM_MenuBarPanelWidth. midLineWidth в настоящее время всегда равно 0.
Это стиль, который отрисовывает заголовки представлений элементов Qt. Представления элементов сохраняют размерности в отдельных секциях. Также обратите внимание на то, что делегаты могут использовать стиль для рисования украшений и рамок вокруг элементов. QItemDelegate, например, отрисовывает PE_FrameFocusRect и PE_IndicatorViewItemCheck.
Вот показан заголовок QTableWidget в стиле Java с ограничивающими прямоугольниками:
QHeaderView использует CT_HeaderSection, PM_HeaderMargin и PM_HeaderGripMargin для вычисления размеров и проверки попадания. PM_HeaderMarkSize в настоящее время в Qt не используется. QTableView отрисовывает кнопку в верхнем левом углу (т.е., область, где пересекаются вертикальные и горизонтальные заголовки) как CE_Header.
Опцией стиля для заголовков представлений элементов является QStyleOptionHeader. Представление рисует один заголовок секции в один момент времени, поэтому данные относятся к отрисовываемой секции. Она содержит:
Член | Значение |
---|---|
icon | пиктограмма в заголовке (для отрисовываемой секции). |
iconAlignment | выравнивание (Qt::Alignment) пиктограммы в заголовке. |
orientation | значение Qt::Orientation определяет, будет ли заголовок горизонтальным над представлением или вертикальным слева от него. |
position | значение QStyleOptionHeader::SectionPosition задает местоположение секции заголовка относительно других секций. |
section | содержит отрисовываемую секцию. |
selectedPosition | значение QStyleOptionHeader::SelectedPosition задает местоположение выделенной секции относительно отрисовываемой секции. |
sortIndicator | значение QStyleOptionHeader::SortIndicator описывает направление, в котором будет нарисован индикатор сортировки секции. |
text | текст отрисовываемой секции. |
textAlignment | выравнивание Qt::Alignment текста внутри заголовка секции. |
Индикаторы ветвей в древовидном представлении отрисовываются стилем с помощью PE_IndicatorBranch. Мы понимаем индикаторы здесь как индикаторы, которые описывают отношения узлов в дереве. Общую опцию стиля QStyleOption отправляют в стиль для рисования этих элементов. Различные виды ветвей описываются состояниями. Так как нет отдельной опции стиля мы просто представим таблицу состояний:
Состояние | Когда устанавливается |
---|---|
State_Sibling | узел в дереве имеет соседние элементы (т.е., имеется другой узел в том же столбце). |
State_Item | данный индикатор ветви имеет элемент. |
State_Children | ветвь имеет дочерние элементы (т.е., новое поддерево может быть открыто в этой ветви). |
State_Open | индикатор ветви имеет открытое поддерево. |
Древовидное представление (и виджет-дерево) использует стиль для рисования ветвей (или узлов, если хотите) дерева.
QStyleOption используемая стилем для PE_IndicatorBranch, имеет флаги состояния устанавливаемые в зависимости от типа ветви.
Так как нет структуры дерева для индикаторов ветвей, мы представим только рисунок дерева в стиле java. Каждое состояние отмечено на рисунке с помощью прямоугольника определенного цвета (т.е., эти прямоугольники не являются ограничивающими прямоугольниками). Все сочетания состояний вы можете узнать из этого рисунка.
PM_SmallIconSize для sizeHint'ов.
QToolBox - это контейнер, в котором хранится коллекция виджетов. Для каждого виджета имеется одна вкладка и в каждый момент времени видна только одна из них. Панель инструментов располагает отображаемые компоненты (кнопки панели инструментов и выбранный виджет) в QVBoxLayout. Дерево стиля для панелей инструментов выглядит примерно так:
Изображение панели инструментов в стиле Plastique:
Все элементы обладают одними и теми же ограничивающими прямоугольниками в стиле так же как и в остальных встроенных стилях Qt.
Опцией стиля для панелей инструментов является QStyleOptionToolBox. Она включает в себя текст и пиктограмму, содержащиеся в панели инструментов. Единственным устанавливаемым QToolBox состоянием является State_Sunken, которое устанавливается когда пользователь щелкает по вкладке (tab down) с помощью мыши. Остальные члены QStyleOptionToolBox:
Член | Значение |
---|---|
icon | пиктограмма вкладки панели инструментов |
text | текст вкладки панели инструментов |
Элемент изменения размеров вычисляет свою подсказку размеров с помощью CT_SizeGrip. В настоящее время пиксельная метрика PM_SizeGripSize не используется Qt. Дерево элементов и изображение QSizeGrip в стиле Plastique следующие:
Мы показали элемент изменения размеров в нижнем правом углу QMainWindow.
Опция стиля элемента изменения размера, QStyleOptionSizeGrip, имеет один член за исключением общих членов из QStyleOption:
Член | Значение |
---|---|
corner | значение Qt::Corner, описывающее в каком углу окна (или эквивалента) располагается элемент изменения размера. |
Дерево стиля QRubberBand состоит из двух узлов.
Представляем изображение окна в стиле Java, перемещаемое в QMdiArea с помощью резиновых линий:
Опция стиля для резиновых линий - QStyleOptionRubberBand. Ее члены:
Член | Значение |
---|---|
opaque | булевое значение, равное true если резиновая линия должна быть нарисована непрозрачном (opaque) стиле (т.е., цветом) |
shape | значение перечисления QRubberBand::Shape, которое содержит форму полосы (band) (которая равна либо прямоугольнику, либо линии) |
При размещении содержимого присоединяемые виджеты запрашивают у стиля следующие пиксельные метрики: PM_DockWidgetSeparatorExtent, PM_DockWidgetTitleBarButtonMargin, PM_DockWidgetFrameWidth и PM_DockWidgetTitleMargin. Они также вычисляют ограничивающие прямоугольники кнопок отделения (float) и закрытия (close) с помощью SE_DockWidgetCloseButton и SE_DockWidgetFloatButton.
Пунктирные линии указывают, что отправитель сохраняет экземпляры класса приемника, указываемого стрелкой (т.е., это элемент стиля не для отрисовки). Присоединяемый виджет рисует PE_frameDockWidget только тогда, когда он отсоединен от своего главного окна (т.е., является окном верхнего уровня). Если он присоединен, он рисует индикатор метки-манипулятора изменения размера присоединяемого окна. Покажем для присоединяемого виджета в стиле plastique оба случая - когда он присоединен и отсоединен:
Опцией стиля является QStyleOptionDockWidget:
Член | Значение |
---|---|
closeable | булевое значение, определяющее может ли присоединяемый виджет быть закрыт |
floatable | булевое значение, определяющее будет ли присоединяемое окно плавающим (т.е., может ли оно отсоединиться от главного окна, в котором "живет") |
movable | булевое значение, определяющее будет ли окно перемещаемым (т.е., можно ли передвигать его к другим областям присоединения виджетов) |
title | текст заголовка присоединяемого окна |
Для кнопок используется QStyleOptionButton (смотрите описание содержимого Инструментальных кнопок). Метка-манипулятор изменения размера присоединяемого виджета имеет простую опцию стиля QStyleOption.
[Предыдущая: Классы виджетов] [Виджеты и компоновки] [Следующая: Таблицы стилей]
Авторские права © 2010 Nokia Corporation и/или её дочерние компании | Торговые марки | Qt 4.6.4 |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |