by Mark Summerfield |
QT класс QListView может обеспечить отображение данных в виде списка и дерева, и способен представлять большие объемы информации. Но он может иметь только 1 фоновый цвет, и один шрифт для всех своих составляютщих.Те же самые правила действуют и для QListBox. В этой статье мы представляем субкласс QListBox и список просмотров компонентов, которые могут иметь свои шрифты и фоновые цвета.
Различные элементы листбокса |
Субкласс элементов листбокса краток и прост. Каждый элемент может иметь свой шрифт, и фоновый цвет, как и показывает скриншот.
Вот объявление этого субкласса :
class FancyListBoxText : public QListBoxText { public: FancyListBoxText(QListBox *parent) : QListBoxText(parent), mFont(parent->font()), mBackground(parent->colorGroup().base()) {} void paint(QPainter *painter); int width(const QListBox *) const { return QFontMetrics(mFont).width(text()); } int height(const QListBox *) const { return QFontMetrics(mFont).height(); } void setText(const QString &text) { QListBoxText::setText(text); } QFont font() const { return mFont; } void setFont(const QFont &font) { mFont = font; } QColor background() const { return mBackground; } void setBackground(const QColor &color) { mBackground = color; } private: QFont mFont; QColor mBackground; };
Кроме функции paint(), весь код приведен в объявлении непосредственно. Мы должны убедиться, что мы задаем осмысленные значения по умолчанию для шрифта и фона в конструкторе. Мы должны также реимплементировать width() и height(), потому что нестандартный шрифт может повлиять на размер элемента списка.
void FancyListBoxText::paint(QPainter *painter) { QFont font = painter->font(); painter->setFont(mFont); painter->fillRect(painter->viewport(), mBackground); QListBoxText::paint(painter); painter->setFont(font); }
В функции paint() мы сохранили оригинальный шрифт, и установили шрифт в требуемый. Далее покрасили фон, и после этого выполнили остальную часть работы. Наконец, мы окончили работу, восстановив оригинальный шрифт. Более медленной альтернативой было бы сохранение состояния painter'а, установка шрифта и восстановление его состояния в конце.
Это то, что необходимо было сделать. Сейчас мы можем создать FancyListBoxText элементы, вместо обычных QListBoxText элементов.
Нестандартные формы представления списка |
Теперь – наш элемент просмотра списков добавит шрифт и фон для каждой колонки.
Объявление нашего субкласса будет выглядеть так :
class FancyListViewItem : public QListViewItem { public: FancyListViewItem(QListView *parent, const QString &label1, const QString &label2) : QListViewItem(parent, label1, label2) {} FancyListViewItem(QListViewItem *parent, const QString &label1, const QString &label2) : QListViewItem(parent, label1, label2) {} void paintCell(QPainter *painter, const QColorGroup &cg, int column, int width, int align); int width(const QFontMetrics &fm, const QListView *lv, int column) const; QFont font(uint column) const; void setFont(uint column, const QFont &font); QColor background(uint column) const; void setBackground(uint column, const QColor &color); private: QValueVector<QFont> fonts; QValueVector<QColor> backgrounds; };
Мы создали только два конструктора для элементов с двумя строками, но нетрудно сделать остальные, поскольку они будут просто вызывать базовый класс и не иметь собственной функциональности. Мы сохраняем шрифт и фон каждой колонки в двух приватных QValueVector.
QFont FancyListViewItem::font(uint column) const { if (column < fonts.size()) return fonts[column]; return listView()->font(); }
Если шрифт был установлен – мы его возвратим, иначе – мы возвратим шрифт QListView.
void FancyListViewItem::setFont( uint column, const QFont &font) { if (column >= fonts.size()) fonts.resize(column + 1, listView()->font()); fonts[column] = font; }
QColor FancyListViewItem::background(uint column) const { if (column < backgrounds.size()) return backgrounds[column]; return listView()->colorGroup().base(); }
Тут использована та же логика, что и font().
void FancyListViewItem::setBackground(uint column, const QColor &color) { if (column >= backgrounds.size()) backgrounds.resize(column + 1, listView()->colorGroup().base()); backgrounds[column] = color; }
А здесь мы использовали базовый цвет QListView как цвет по умолчанию для пустых элементов.
void FancyListViewItem::paintCell( QPainter *painter, const QColorGroup &cg, int column, int width, int align) { painter->save(); if (column >= 0 && column < (int)fonts.size()) painter->setFont(fonts[column]); QColorGroup grp(cg); if (column >= 0 && column < (int)backgrounds.size()) grp.setColor(QColorGroup::Base, backgrounds[column]); QListViewItem::paintCell(painter, grp, column, width, align); painter->restore(); }
В начале сохраняем состояние пейнтера. Если у нас выбран нестандартный шрифт, мы задаем его пейнтеру. Мы создаем новую цветовую группу, копируя ее из переданной, и если мы имеем свой фон, мы его устанавливаем для группы-копии. Затем мы вызываем стандартную функцию отрисовки элемента списка с нашими новыми параметрами. После этого необходимо установить пейнтер в его первоначальное состояние.
int FancyListViewItem::width(const QFontMetrics &fm, const QListView *lv, int column) const { int width; if (column >= 0 && column < (int)fonts.size()) { QFontMetrics fm2(fonts[column]); width = QListViewItem::width(fm2, lv, column); } else width = QListViewItem::width(fm, lv, column); return width; }
Если бы мы использовали свой шрифт – возможно, что он был бы шире, или уже, чем стандартный шрифт QListView. Так что необходимо перерасчитать ширину.
Для создания скриншотов, мы прошли по именам цветов и шрифтов, применяемым в Qt. Для получения имен цветов мы применяли статическую функцию QColor::colorNames(). Имена из этого списка могут быть переданы в конструктор QColor. Для получения списка имен шрифтов мы применяли QFontDatabase().families(). Имена из этого списка могут быть переданы в конструктор QFont. |
Copyright © 2003 Trolltech | Trademarks |