Давайте разберемся как в заголовках колонок таблицы (QHeaderView) помимо текста выводить разную дополнительную информацию. Например в нашем случае есть необходимость выводить значок (иконку), означающий, что по какой-то колонке сделан отбор.
QHeaderView отрисовывает каждую секцию заголовка в функции QHeaderView::paintSection, давайте ее разберем, тут все вроде бы на первый взгляд очевидно:
void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
Q_D(const QHeaderView);
if (!rect.isValid())
return;
// get the state of the section
QStyleOptionHeader opt;
initStyleOption(&opt);
QStyle::State state = QStyle::State_None;
if (isEnabled())
state |= QStyle::State_Enabled;
if (window()->isActiveWindow())
state |= QStyle::State_Active;
if (d->clickableSections) {
if (logicalIndex == d->hover)
state |= QStyle::State_MouseOver;
if (logicalIndex == d->pressed)
state |= QStyle::State_Sunken;
else if (d->highlightSelected) {
if (d->sectionIntersectsSelection(logicalIndex))
state |= QStyle::State_On;
if (d->isSectionSelected(logicalIndex))
state |= QStyle::State_Sunken;
}
}
if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
// setup the style options structure
QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
Qt::TextAlignmentRole);
opt.rect = rect;
opt.section = logicalIndex;
opt.state |= state;
opt.textAlignment = Qt::Alignment(textAlignment.isValid()
? Qt::Alignment(textAlignment.toInt())
: d->defaultAlignment);
opt.iconAlignment = Qt::AlignVCenter;
opt.text = d->model->headerData(logicalIndex, d->orientation,
Qt::DisplayRole).toString();
if (d->textElideMode != Qt::ElideNone)
opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4);
QVariant variant = d->model->headerData(logicalIndex, d->orientation,
Qt::DecorationRole);
opt.icon = qvariant_cast(variant);
if (opt.icon.isNull())
opt.icon = qvariant_cast(variant);
QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
Qt::ForegroundRole);
if (foregroundBrush.canConvert())
opt.palette.setBrush(QPalette::ButtonText, qvariant_cast(foregroundBrush));
QPointF oldBO = painter->brushOrigin();
QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
Qt::BackgroundRole);
if (backgroundBrush.canConvert()) {
opt.palette.setBrush(QPalette::Button, qvariant_cast(backgroundBrush));
opt.palette.setBrush(QPalette::Window, qvariant_cast(backgroundBrush));
painter->setBrushOrigin(opt.rect.topLeft());
}
// the section position
int visual = visualIndex(logicalIndex);
Q_ASSERT(visual != -1);
if (count() == 1)
opt.position = QStyleOptionHeader::OnlyOneSection;
else if (visual == 0)
opt.position = QStyleOptionHeader::Beginning;
else if (visual == count() - 1)
opt.position = QStyleOptionHeader::End;
else
opt.position = QStyleOptionHeader::Middle;
opt.orientation = d->orientation;
// the selected position
bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
bool nextSelected = d->isSectionSelected(this->logicalIndex(visual 1));
if (previousSelected && nextSelected)
opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
else if (previousSelected)
opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
else if (nextSelected)
opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
else
opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
// draw the section
style()->drawControl(QStyle::CE_Header, &opt, painter, this);
painter->setBrushOrigin(oldBO);
}
На практике получается, что цвет текста в колонке заголовка меняется нормально через роль TextColorRole. А вот цвет фона секции через роль BackgroundColorRole не устанавливается.
Вот кусок стека вызовов функций при отрисовки секции:
QHeaderView::paintEvent
QHeaderView::paintSection // для каждой секции отдельно, тут мы видим, что backgroundBrush устанавливается при использовании роли Qt::BackgroundRole (то есть пока все нормально)
QWindowsVistaStyle::drawControl
QWindowsXPStyle::drawControl
QWindowsStyle::drawControl
QCommonStyle::drawControl //
Итак что именно не срабатывает в QCommonStyle::drawControl а именно в case CE_Header, чтобы изменился фон секции? Переопределяем функцию и выясняем, что:
style()->drawControl(QStyle::CE_HeaderLabel, &subopt, painter, this); // рисует текст в секции - это понятно.
style()->drawControl(QStyle::CE_HeaderSection, &header, painter, this); // отвечает каким-то образом за фон (но как цвет фона изменить по прежнему не понятно).
Как подсказку используем лог функции data и подсмотрим какие роли запрашивает QTableView у модели данных (для отрисовки себя конечно же). Оказывается это:
Qt::FontRole
Qt::TextAlignmentRole
Qt::TextColorRole
Qt::CheckStateRole
Qt::DecorationRole
Qt::BackgroundColorRole
DecorationRole отвечает за иконку например и этим можно воспользоваться. То есть можно штатными средствами установить заголовку колонки иконку слева или справа. Вот пример:
Можно добавить, что через setStyleSheet можно менять по выделенной ячейки цвет фона ячейки в заголовке, как на картинке ниже:
Наше развитие модели - представления Qt и все удобные плюшки с этим связанные можно скачать здесь Развитие Sql Qt 4.8.1
.