Лента? Это Просто! Или Работа С Каскадными Таблицами Стилей (Css) В Qt

Некоторое время назад в одном из обсуждений я упоминал, что элемент управления «а-ля лента» (который использовался в MS Office 2007 для организации меню) легко и естественно реализуется с помощью Qt. Не хочу спорить о том, удобна лента или нет (сам больше склоняюсь ко второму мнению).

Но его пример может прекрасно раскрыть возможности каскадных таблиц стилей для Qt (которые были представлены в Qt 4.2), чем я и займусь.

Сразу извиняюсь: я не дизайнер, поэтому с эстетической точки зрения мой QRibbon скорее всего не дотянет до своего собрата из MS, но дизайнеры в MS, я считаю, превосходят меня на две головы в своей области, и я думаю, что есть также человеко-часы, потраченные на немного более.

Я лишь демонстрирую общий принцип и базовые возможности.

Так как сейчас я изучаю язык Python, то для демонстрации был выбран именно он, а для C++ все сделано точно так же.

Заранее извиняюсь: я только изучаю Python, поэтому код может быть корявым, поэтому, пожалуйста, не обижайте меня :) Итак, начнем!



Создание скелета

Возьмем за основу стандартный QTabWidget, потому что.

он здесь напрашивается сам.

Страницы мы будем делать из виджетов, имеющих горизонтальную раскладку (QHBoxLayout), последний элемент которых — QSpacerItem (не знаю, как его назвать по-русски, но это такая невидимая штука, которая заполняет свободное пространство :)).

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
   

#!/usr/bin/python from PyQt4 import Qt, uic import sys # Class that represents a ribbon page class Tab(Qt.QWidget) : def __init__(self) : Qt.QWidget.__init__(self) # create the spacer and the layout and set it as a widget main layout self.spacer = Qt.QSpacerItem(10, 10, Qt.QSizePolicy.Expanding) self.layout = Qt.QHBoxLayout() self.layout.addSpacerItem(self.spacer) self.setLayout(self.layout) # Class that represents a ribbon class QRibbon(Qt.QTabWidget) : def __init__ (self) : Qt.QTabWidget.__init__(self) self.resize(450, 170) # storage for tabs self.tabs = dict() def addTab(self, tabName) : # check if tab with this name already exists if not tabName in self.tabs : newTab = Tab() self.tabs[tabName] = newTab Qt.QTabWidget.addTab(self, newTab, tabName) def addPane(self, tabName, pane) : # check if tab with this name exists if tabName in self.tabs : tab = self.tabs[tabName] tab.layout.insertWidget(tab.layout.count() - 1, pane) if __name__ == "__main__" : app = Qt.QApplication(sys.argv) ribbon = QRibbon() # add a couple of tabs ribbon.addTab(ribbon.tr('Home')) ribbon.addTab(ribbon.tr('Insert')) ribbon.show() app.exec_()

Теперь открываем QtDesigner и рисуем панели, которые добавим на «страницы» нашей ленты.

В мои планы не входит воспроизводить панель попиксельно, я просто покажу, как можно поиграться с разными кнопками и раскрасить их с помощью таблицы стилей.

Давайте сделаем первую панель такой:

Лента? Это просто! или работа с каскадными таблицами стилей (CSS) в Qt

Он будет иметь большую кнопку «Вставить» и две кнопки поменьше: «Вырезать» и «Копировать».

Вторая панель будет панелью шрифтов.

Разместим на нем комбо-поля для выбора семейства шрифта и его размера, а также «выпадающие» кнопки «Жирный», «Курсив» и «Подчеркнутый»:

Лента? Это просто! или работа с каскадными таблицами стилей (CSS) в Qt

Каждую из панелей мы сделаем отдельным виджетом (отдельным классом).

Этот класс будет загружать свой ui-файл (который мы рисуем в дизайнере) и обрабатывать сигналы от элементов управления (эту часть я пропущу, так как она не имеет прямого отношения к нашей теме).

Итак, добавим базовый класс панели (пока он не несет никакой нагрузки, но в будущем можно будет через него назначать панелям некоторые общие свойства, например стиль) и 2 класса панелей:

class Pane(Qt.QWidget) : def __init__(self) : Qt.QWidget.__init__(self) class ClipboardPane(Pane) : def __init__(self) : Pane.__init__(self) uiClass, qtBaseClass = uic.loadUiType('edit.ui') self.ui = uiClass() self.ui.setupUi(self) # set icons for buttons self.ui.pasteBtn.setIcon(Qt.QIcon('paste.png')) self.ui.pasteBtn.setIconSize(Qt.QSize(48, 48)) self.ui.cutBtn.setIcon(Qt.QIcon('cut.png')) self.ui.copyBtn.setIcon(Qt.QIcon('copy.png')) class FontPane(Pane) : def __init__(self) : Pane.__init__(self) uiClass, qtBaseClass = uic.loadUiType('font.ui') self.ui = uiClass() self.ui.setupUi(self)

Ну а в основной функции мы добавим наши панели на «Главную» страницу:

if __name__ == "__main__" : .

# add two panes to "Home" page ribbon.addPane(ribbon.tr('Home'), ClipboardPane()) ribbon.addPane(ribbon.tr('Home'), FontPane()) .

app.exec_()

В итоге получаем вот это чудо:

Лента? Это просто! или работа с каскадными таблицами стилей (CSS) в Qt



"Останавливаться!" — Думаю про себя: «Что-то здесь не так».

Очертания вроде бы видны, но лента явно «не торт»… Спокойно, просто спокойно, приступим к самому интересному! Итак, создадим вспомогательную функцию, читающую и возвращающую содержимое файла (мы будем использовать ее для чтения таблиц стилей из файлов) и добавим в конструкторы классов QRibbon и Pane строку, читающую соответствующий файл стиля:

def readStyleSheet(fileName) : css = Qt.QString() file = Qt.QFile(fileName) if file.open(Qt.QIODevice.ReadOnly) : css = Qt.QString(file.readAll()) file.close() return css class QRibbon(Qt.QTabWidget) : def __init__ (self) : .

self.setStyleSheet(readStyleSheet('qribbon.qss')) class FontPane(Pane) : def __init__(self) : .

self.setStyleSheet(readStyleSheet('page.qss'))

Думаю, было бы лучше, если бы кнопки «Вырезать», «Копировать» и «Вставить» сделали плоскими.

Зайдем в QtDesigner и установим для них соответствующий атрибут. Ну а теперь приступим к самому интересному: созданию CSS, который преобразит нашу ленту до неузнаваемости!

«Раскрась сам»

Сначала давайте посмотрим на таблицу стилей главного окна (qribbon.qss).

Синтаксис 1-в-1 скопирован из CSS, поэтому я дам только общие комментарии, поскольку код говорит сам за себя: Установите цвет фона виджетов:

QWidget { background-color: #d0d9f0; }

Сделаем верхнюю границу панелей более привлекательной:

QTabWidget::pane { border-top: 2px solid qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #90a0e0, stop:1.0 #303070); }

Здесь требуется небольшое пояснение.

С помощью первых 4 параметров задается направление: из левого верхнего угла в левый нижний, т.е.

вертикально вниз.

Далее идут контрольные точки (принимайте значения от 0 до 1) и их цвета.

В данном случае мы имеем простой градиент: он идет от нуля до единицы без дополнительных промежуточных точек.

Зададим небольшой отступ для табуляции:

QTabWidget::tab-bar { left: 30px; }

Зададим отступы для каждой из вкладок на панели вкладок, а также изменим цвет текста и закруглим углы вкладок:

QTabBar::tab { padding: 5px 15px 3px 15px; margin-top: 10px; color: #303070; border-top-left-radius: 4px; border-top-right-radius: 4px; }

Давайте изменим цвет вкладки при наведении курсора:

QTabBar::tab:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fffaff, stop: 0.4 #fff0c0, stop: 0.5 #fff0c0, stop: 1.0 #d0d9f0); border: 1px solid #a4a063; }

Здесь градиент немного сложнее: у него есть 2 промежуточные «контрольные точки»: 0,4 и 0,5. Давайте присвоим неактивной вкладке стиль нижней границы, соответствующий верхней границе панелей (см.

выше):

QTabBar::tab:!selected { border-bottom: 2px solid qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #90a0e0, stop:1 #303070); }

Давайте изменим стиль активной вкладки и удалим ее нижнюю границу:

QTabBar::tab:selected { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f0f0ff, stop: 0.4 #f4f4ff, stop: 0.5 #e7e7ff, stop: 1.0 #d0d9f0); border: 1px solid #808090; border-bottom: solid 0px; }

Немного изменим стиль кнопок:

QPushButton { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6fcff, stop: 1.0 #a0b0d0); border: 1px solid #a0a0b0; border-radius: 3px; }

Давайте изменим цвет «утопленных» кнопок:

QPushButton:checked { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f0eeaa, stop: 1 #eeaa88); }

Давайте спрячем «плоские» кнопки.

Пусть будет видно только содержимое:

QPushButton:flat { border: none; background: none; }

«Оживим» кнопки в момент нажатия:

QPushButton:pressed { background-color: #e0e3ff; }

Давайте посмотрим, что произошло:

Лента? Это просто! или работа с каскадными таблицами стилей (CSS) в Qt

Хм, кажется, становится лучше, не так ли? Осталось только добавить немного шарма панелям с элементами управления.

Давайте создадим файл page.qss:

QFrame { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6fcff, stop: 1.0 #a0b0d0); border: 1px solid #8080a0; border-top-left-radius: 4px; border-top-right-radius: 4px; } QLabel { color: #303070; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #c6cccf, stop: 1.0 #90a0b0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-top: 0px; }

Вот и все.

Теперь давайте вспомним, как выглядела наша лента до того, как мы применили стили, и сравним ее с тем, как она выглядит сейчас:

Лента? Это просто! или работа с каскадными таблицами стилей (CSS) в Qt



Лента? Это просто! или работа с каскадными таблицами стилей (CSS) в Qt

Неплохо, правда? :) (комбобоксы, конечно, тоже можно настроить, но это я оставлю как домашнее задание) Подробную документацию по использованию стилей в Qt можно найти по адресу: doc.trolltech.com/4.2/stylesheet.html Мой единственный совет тем, кто пользуется этим вводным руководством и будет использовать стили в своих программах: помещайте стили во внешние файлы.

В этом случае, даже если немного переусердствовать, пользователь сможет подправить пользовательский интерфейс без необходимости дизассемблирования программного кода.

Архив с исходниками здесь .

Теги: #python #qt4 #pyqt4 #CSS #Qt

Вместе с данным постом часто просматривают: