
На скриншоте приведен один из диалогов нашего органайзера для студентов, весь интерфейс которого реализован на QSS.
На том же скриншоте мы видим основные элементы интерфейса, кастомизацию которых сегодня и разберем:
- Сегментные кнопки
- Обычные кнопки
- Таблицы
- Скроллбары
Основы
Но сначала разберемся с некоторыми базовыми вещами. Мы можем применять стили как локально (к конкретному виджету), так и глобально, вынося все стили в отдельный файл. Преимущества второго подхода очевидны всем, кто хоть раз работал с CSS, потому на нем мы и остановимся.
Я категорически рекомендую пользоваться системой ресурсов Qt, которая позволяет не заморачиваться и вкомпилировать картинки и файлы стилей прямо в бинарник.
Итак, создаем файл стилей, применяем его глобально к приложению:
QFile styleF; styleF.setFileName(":/qss/style.css"); styleF.open(QFile::ReadOnly); QString qssStr = styleF.readAll(); qApp->setStyleSheet(qssStr);
Есть отличный перевод официальной документации по синтаксису таблиц стилей, так что замечу лишь, что чаще других используется три способа описания виджетов, к которым будет применен стиль (селекторы):
Обращение по классу, например такое правило будет применено ко всем кнопкам вашего приложения, цвет фона будет изменен на красный:
QPushButton { background-color: red; }
Обращение по имени, тогда это правило будет применено только к тем кнопкам, которые имеют имя «okButton»:
QPushButton#okButton { background-color: red; }
Причем если на одной и той же форме есть несколько элементов, к которым нужно применить одинаковый стиль, можно воспользоваться методом setObjectName:
ui->pbRed1->setObjectName("myRedButton"); ui->pbRed2->setObjectName("myRedButton");
Обращение по иерархии виджетов на форме, тогда правило будет применено только к тем кнопкам, которые лежат внутри рамки с именем «mainFrame»:
QFrame#mainFrame QPushButton{ background-color: red; }
Отдельно нужно сказать о задании стилей для подэлементов и псевдо-состояний:
Псевдо-состояния указываются в конце селектора, отделяются двоеточием (:). Например, следующее правило применяется, когда мышь находится над QPushButton:
QPushButton:hover { background-color: white }
Сложные виджеты содержат в себе подэлементы, потому для изменения оформления можно получить доступ к каждому из них, для этого используется оператор "::". Например, мы хотим изменить/убрать стрелочку, показывающую, что кнопке назначено меню, в таком случае правило будет выглядеть следующим образом:
QPushButton#menuButton::menu-indicator { image: url(:/img/other/myindicator.png); }
К сожалению, чтобы описать все возможности потребуется полнокровный учебник по CSS, потому переходим к примерам.
Кнопки сегментные
У меня две новости: одна хорошая, а другая не очень. Печаль в том, что QSS не поддерживает отрисовку теней. Совсем. Потому если сделать обычное состояние сегментных кнопок в общем-то не сложно, то нажатое… в общем только картинки.
Вот стили, ответственные за это безобразие:
QPushButton#pbDelRight { image: url(:/img/buttons//pbDelRight.png); border-top-right-radius: 4px; border-bottom-right-radius: 4px; height: 26px; width: 40px; } QPushButton#pbDelRight:pressed { image: url(:/img/buttons/pbDelRightPressed.png); } QPushButton#pbDelRight:checked { image: url(:/img/buttons/pbDelRightPressed.png); }
Состояние :pressed нужно указывать для того, чтобы не было лага при его прохождении.
OS X bug: Если не выставить кнопкам свойство flat, они будут налезать друг на друга.
Кнопки обыкновенные
Мне известны только два варианта отображения нажатого состояния без использования теней — отразить градиент и обратить цвета. Рассмотрим второй вариант:
QPushButton#pbReady { padding:4px; color: #fff; font-size: 14px; border-radius: 2px; border: 1px solid #3873d9; background-color: qlineargradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #4287ff, stop: 1 #356ccc); } QPushButton#pbReady:pressed { color: #111; border: 1px solid #3873d9; background: #fff; }
Таблицы
Кастомизация таблиц сделана весьма добротно, отдельно задаются стили для шапки, отдельно для самой таблицы. Есть возможность задать стили для определенных колонок (секций) шапки через подэлемент ::section. Для этого реализованы псевдо-состояния :first, :last, :only-one, :next-selected, :previous-selected, :selected, :horizontal, :vertical и :checked.
QHeaderView { background-color: #fff; font-size:13px; } QHeaderView::section:horizontal { color: #fff; border-style: solid; background-color: qlineargradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #4287ff, stop: 1 #356ccc); } QTableView { border: 2px solid #3873d9; border-top-color: #4287ff; border-radius: 4px; background-color: #fff; background-image: url(:/img/other/background.png); gridline-color: #777; selection-background-color: #ccdfff; color:#333; font-size:12px; }
Скроллбары
Основными настраиваемыми элементами являются две стрелочки по краям и хэндл, за который, собственно можно ухватить мышкой:
QScrollBar:vertical { background: #e4e4e4; border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 12px; margin: 0px; } QScrollBar::handle:vertical { background-color: qlineargradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #4287ff, stop: 1 #356ccc); border-radius: 4px; min-height: 20px; margin: 0px 2px 0px 2px; } QScrollBar::add-line:vertical { background: none; height: 0px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { background: none; height: 0px; subcontrol-position: left; subcontrol-origin: margin; }
На OS X начиная с 10.9 используются
волшебныеисчезающие скроллбары, Qt их поддерживает, так что переопределять не стоит.
Со скроллбарами связан кроссплатформенный баг, из-за которого нижний/правый край скроллбара отрисовывается поверх объекта скроллинга, если тот имеет обводку через QSS.
P.S. Примеры использования QSS при кастомизации каждого конкретного виджета можно посмотреть здесь, справочник возможных свойств, состояний и подэлементов тут. Ну и статья на хабре с попыткой реализации Ribbon-интерфейса, возможно будет интересно почитать.
ссылка на оригинал статьи http://habrahabr.ru/company/istodo/blog/216275/
Добавить комментарий