Wiki

Различные элементы списка

by Mark Summerfield

QT класс QListView может обеспечить отображение данных в виде списка и дерева, и способен представлять большие объемы информации. Но он может иметь только 1 фоновый цвет, и один шрифт для всех своих составляютщих.Те же самые правила действуют и для QListBox. В этой статье мы представляем субкласс QListBox и список просмотров компонентов, которые могут иметь свои шрифты и фоновые цвета.

Различные элементы листбокса

Субкласс элементов листбокса краток и прост. Каждый элемент может иметь свой шрифт, и фоновый цвет, как и показывает скриншот.

Fancylistbox

Вот объявление этого субкласса :

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 элементов.

Нестандартные формы представления списка

Теперь – наш элемент просмотра списков добавит шрифт и фон для каждой колонки.

Fancylistview

Объявление нашего субкласса будет выглядеть так :

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;
}
Когда шрифт установлен – мы произведем перерасчет вектора, если будет необходимость. По умолчанию пустые элементы QValueVector заполняются T(). Если же мы до сих пор не определили шрифт – мы должны использовать конструктор QFont(), который создаст шрифт приложенияпо умолчанию, могущий отличаться от шрифта QListView.
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;
}&nbsp;

А здесь мы использовали базовый цвет 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

Для создания скриншотов, мы прошли по именам цветов и шрифтов, применяемым в Qt. Для получения имен цветов мы применяли статическую функцию QColor::colorNames(). Имена из этого списка могут быть переданы в конструктор QColor. Для получения списка имен шрифтов мы применяли QFontDatabase().families(). Имена из этого списка могут быть переданы в конструктор QFont.


Copyright © 2003 Trolltech Trademarks