Russian Qt Forum
Октябрь 01, 2024, 20:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: HeaderView с мультистолбцовой сортировкой и меню (скрыть/показать столбцы)  (Прочитано 7024 раз)
asvil
Гость
« : Январь 11, 2010, 21:38 »

Класс унаследованный от QHeaderView. Знаю что велосипед, но уже никуда не денешься.
В отсортированном столбце заголовка справа от названия столбца появляется число порядка сортировки и стрелочка (ASC, DESC). Логика работы стрелочек лежит на представлении. Сам HeaderView с моделью по поводу сортировок не общается. Сигналов об изменении порядков, стрелочек не подает. Протестировано под мандривой 2010 с установленной qt 4.5.3.

В paintSection в случае сортировки, я отжевываю справа местечко длиной 35 пикселов и там через структуру стиля вывожу число и стрелочку, и вызываю родительскую отрисовку. Не самый лучший вариант, но быстрый.
Думалось конечно по-взрослому отнаследовать приватный QHeaderView переписать paintSection полностью, но как-то это небинарно совместимо.


// Удалить индикатор сортировки
   void removeSortIndicator(int logicalIndex);
   // Удалить все индикаторы сортировки
   void clearSortIndicators();
   // Установлен ли индикатор
   bool isSortIndicatorShown(int logicalIndex) const;
   // Установить индикатор, если это уже второй индикатор справа отобразить число порядка
// Если clearPrevious все стрелочки в столбцах удаляются
// Если clearPrevious == false добавляется новая стрелочка с номером порядка ее добавления.
   void setSortIndicator(int logicalIndex, Qt::SortOrder order, bool clearPrevious = true);
   // Какая стрелочка отображена для данной колонки. Если никакой, то результат Qt::Asceding
   Qt::SortOrder sortIndicatorOrder(int logicalIndex) const;
// Список столбцов в которых производилась сортировка в том порядке в котором они добавлялись
   QList<int> sortIndicatorSections() const;
   // Отрисовка
   void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;

headerview_p.h
Код:
#ifndef HEADERVIEW_P_H
#define HEADERVIEW_P_H

#include "kernel/headerview.h"

class QAction;
class HeaderViewPrivate {
Q_DECLARE_PUBLIC(HeaderView);
public:
HeaderViewPrivate(){}

QHash<int, Qt::SortOrder > sortingColumns; //< section, SortOrder>
QList<int> orderList;
HeaderView * q_ptr;

QAction *showHideColumnsActionMenu;
QMenu *showHideColumnsMenu;
QList<QAction *> showHideColumnsActionList;
};

#endif // HEADERVIEW_P_H

headerview.h
Код:
#ifndef HEADERVIEW_H
#define HEADERVIEW_H

#include <QtGui/QHeaderView>

class HeaderViewPrivate;
class HeaderView : public QHeaderView
{
Q_OBJECT
Q_DECLARE_PRIVATE(HeaderView);
public:
HeaderView(Qt::Orientation orientation, QWidget* parent = 0);

// MultiSorting
// Удалить индикатор сортировки
void removeSortIndicator(int logicalIndex);
// Удалить все индикаторы сортировки
void clearSortIndicators();
// Установлен ли индикатор
bool isSortIndicatorShown(int logicalIndex) const;
// Установить индикатор, если это уже второй индикатор справа отобразить число порядка
// Если clearPrevious все стрелочки в столбцах удаляются
void setSortIndicator(int logicalIndex, Qt::SortOrder order, bool clearPrevious = true);
// Какая стрелочка отображена для данной колонки. Если никакой, то результат Qt::Asceding
Qt::SortOrder sortIndicatorOrder(int logicalIndex) const;
// Список столбцов в которых производилась сортировка в том порядке в котором они добавлялись
QList<int> sortIndicatorSections() const;
// Отрисовка
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;

// Остальное для менюшки Скрыть/показать столбцы
void setModel(QAbstractItemModel* model);
void headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast);
virtual void setSectionHidden(int logicalIndex, bool hide);
virtual void hideSection(int logicalIndex);
virtual void showSection(int logicalIndex);

protected slots:
void sectionsAboutToBeRemoved(const QModelIndex &parent, int logicalFirst, int logicalLast);
void sectionsInserted(const QModelIndex& parent, int logicalFirst, int logicalLast);

void showHideAction_toggled(bool checked);

protected:
void checkOneColumn();

HeaderView(HeaderViewPrivate &dd, Qt::Orientation orientation, QWidget* parent);
HeaderViewPrivate * const d_ptr;
};

#endif // HEADERVIEW_H

headerview.cpp
Код:
#include "kernel/headerview.h"
#include "headerview_p.h"

#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QMenu>
#include <QtGui/QAction>

HeaderView::HeaderView(Qt::Orientation orientation, QWidget* parent)
:QHeaderView(orientation, parent)
, d_ptr(new HeaderViewPrivate())
{
Q_D(HeaderView);
d->q_ptr = this;

d->showHideColumnsActionMenu = new QAction("Показать/скрыть столбцы", this);
d->showHideColumnsMenu = new QMenu(this);
d->showHideColumnsActionMenu->setMenu(d->showHideColumnsMenu);
addAction(d->showHideColumnsActionMenu);
}

HeaderView::HeaderView(HeaderViewPrivate &dd, Qt::Orientation orientation, QWidget* parent)
:QHeaderView(orientation, parent)
, d_ptr(&dd)
{
Q_D(HeaderView);
d->q_ptr = this;
}

void HeaderView::removeSortIndicator(int logicalIndex)
{
Q_D(HeaderView);
d->sortingColumns.remove(logicalIndex);
d->orderList.removeAll(logicalIndex);
//repaint();
}

void HeaderView::clearSortIndicators()
{
Q_D(HeaderView);
d->sortingColumns.clear();
d->orderList.clear();
//repaint();
}

bool HeaderView::isSortIndicatorShown(int logicalIndex) const
{
Q_D(const HeaderView);
return (d->sortingColumns.contains(logicalIndex));
}

void HeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order, bool clearPrevious)
{
Q_D(HeaderView);
if (clearPrevious)
clearSortIndicators();

if (logicalIndex > -1 && logicalIndex < count()) {
d->sortingColumns.insert(logicalIndex, order);
if (!d->orderList.contains(logicalIndex))
d->orderList.append(logicalIndex);
} else if (logicalIndex == -1)
clearSortIndicators();

repaint();
}

QList<int> HeaderView::sortIndicatorSections() const
{
Q_D(const HeaderView);
return d->orderList;
}

Qt::SortOrder HeaderView::sortIndicatorOrder(int logicalIndex) const
{
Q_D(const HeaderView);

if (d->sortingColumns.contains(logicalIndex))
return d->sortingColumns.value(logicalIndex);

return Qt::AscendingOrder;
}

void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
Q_D(const HeaderView);

if (isSortIndicatorShown(logicalIndex)) {
QRect sortInfoRect(rect.topRight() - QPoint(35,0), rect.bottomRight());

QStyleOptionHeader opt;
initStyleOption(&opt);
QStyle::State state = QStyle::State_None;
if (isEnabled())
state |= QStyle::State_Enabled;
if (window()->isActiveWindow())
state |= QStyle::State_Active;

// not good worked
QPoint cursorPos = mapFromGlobal(cursor().pos());
if (isClickable()) {
if (sortInfoRect.contains(cursorPos)) {
state |= QStyle::State_MouseOver;
if (QApplication::mouseButtons() & Qt::LeftButton)
state |= QStyle::State_Sunken;
}
}

opt.rect = sortInfoRect;
opt.section = logicalIndex;
opt.state |= state;

if (d->orderList.count() > 1) {
int i;
for (i = 0; i < d->orderList.count(); ++i)
if (d->orderList.at(i) == logicalIndex)
break;

opt.text = QString::number(i+1) /*+ (d->sortingColumns.value(logicalIndex)==Qt::AscendingOrder
   ?QString(0x2193) : QString(0x2191))*/;
}
opt.sortIndicator = d->sortingColumns.value(logicalIndex)==Qt::AscendingOrder
   ?QStyleOptionHeader::SortDown
   :QStyleOptionHeader::SortUp;

QVariant foregroundBrush = model()->headerData(logicalIndex, orientation(),
Qt::ForegroundRole);
if (qVariantCanConvert<QBrush>(foregroundBrush))
opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));

QPointF oldBO = painter->brushOrigin();
QVariant backgroundBrush = model()->headerData(logicalIndex, orientation(),
Qt::BackgroundRole);
if (qVariantCanConvert<QBrush>(backgroundBrush)) {
opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(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 = orientation();
// draw the section
style()->drawControl(QStyle::CE_Header, &opt, painter, this);
painter->setBrushOrigin(oldBO);

QRect newRect(rect.topLeft(), rect.bottomRight() - QPoint(35, 0));
QHeaderView::paintSection(painter, newRect, logicalIndex);
} else
QHeaderView::paintSection(painter, rect, logicalIndex);
}

void HeaderView::setModel(QAbstractItemModel* model)
{
Q_D(HeaderView);
for (int i = 0; i < d->showHideColumnsActionList.count(); ++i) {
delete d->showHideColumnsActionList.at(i);
}
clearSortIndicators();
d->showHideColumnsActionList.clear();
QHeaderView::setModel(model);
if (model) {
QAction *inserting;
for (int i = 0; i < model->columnCount(QModelIndex()); ++i) {
inserting = new QAction(model->headerData(i, orientation()).toString(), this);
inserting->setCheckable(true);
inserting->setChecked(true);
d->showHideColumnsActionList.append(inserting);
d->showHideColumnsMenu->addAction(inserting);
connect(inserting, SIGNAL(toggled(bool)),
   this, SLOT(showHideAction_toggled(bool)));
}
checkOneColumn();
}
}

void HeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
{
Q_D(HeaderView);
for (int i = logicalFirst; i <= logicalLast; ++i)
d->showHideColumnsActionList.value(i)->setText(model()->headerData(i, orientation).toString());
QHeaderView::headerDataChanged(orientation, logicalFirst, logicalLast);
}

void HeaderView::setSectionHidden(int logicalIndex, bool hide)
{
Q_D(HeaderView);
if (logicalIndex >= 0 && logicalIndex < d->showHideColumnsActionList.count())
d->showHideColumnsActionList.value(logicalIndex)->setChecked(!hide);
checkOneColumn();
QHeaderView::setSectionHidden(logicalIndex, hide);
}

void HeaderView::hideSection(int logicalIndex)
{
setSectionHidden(logicalIndex, true);
}

void HeaderView::showSection(int logicalIndex)
{
setSectionHidden(logicalIndex, false);
}

void HeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent, int logicalFirst, int logicalLast)
{
Q_D(HeaderView);
if (!parent.isValid()) {
for (int i = logicalFirst; i <= logicalLast; ++i) {
disconnect(d->showHideColumnsActionList.at(i), SIGNAL(toggled(bool)),
   this, SLOT(showHideAction_toggled(bool)));
d->showHideColumnsActionList.removeAt(i);
}
}
checkOneColumn();
QHeaderView::sectionsAboutToBeRemoved(parent, logicalFirst, logicalLast);
}

void HeaderView::sectionsInserted(const QModelIndex& parent, int logicalFirst, int logicalLast)
{
Q_D(HeaderView);
if (!parent.isValid()) {
QAction *inserting;
for (int i = logicalFirst; i <= logicalLast; ++i) {
inserting = new QAction(model()->headerData(i, orientation()).toString(), this);
d->showHideColumnsActionList.insert(i, inserting);
connect(inserting, SIGNAL(toggled(bool)),
   this, SLOT(showHideAction_toggled(bool)));
}
}
checkOneColumn();
QHeaderView::sectionsInserted(parent, logicalFirst, logicalLast);
}

void HeaderView::showHideAction_toggled(bool checked)
{
Q_D(HeaderView);
QAction *senderAction = qobject_cast<QAction *> (sender());
if (senderAction) {
QHeaderView::setSectionHidden(d->showHideColumnsActionList.indexOf(senderAction), !checked);
checkOneColumn();
}
}

void HeaderView::checkOneColumn()
{
Q_D(HeaderView);
if (hiddenSectionCount() + 1 == d->showHideColumnsActionList.count()) {
for (int i = 0; i < d->showHideColumnsActionList.count(); ++i)
if (d->showHideColumnsActionList.value(i)->isChecked()) {
d->showHideColumnsActionList.value(i)->setEnabled(false);
break;
}
} else {
for (int i = 0; i < d->showHideColumnsActionList.count(); ++i)
d->showHideColumnsActionList.value(i)->setEnabled(true);
}
}

Пример использования.
В унаследованном от QtableView классе в конструкторе
Код:
d->horizontalHeader = new HeaderView(Qt::Horizontal, this);
d->horizontalHeader->setClickable(true);
setHorizontalHeader(d->horizontalHeader);
d->horizontalHeader->setMovable(true);
В слоте привязанном к сигналу QHeaderView::clicked(int)
Код:
if (QApplication::keyboardModifiers() & Qt::ControlModifier)
{
if (d->horizontalHeader->sortIndicatorOrder(logicalIndex) == Qt::DescendingOrder) {
d->horizontalHeader->removeSortIndicator(logicalIndex);
d->model->removeSort(logicalIndex);
} else if (!d->horizontalHeader->isSortIndicatorShown(logicalIndex)) {
d->horizontalHeader->setSortIndicator(logicalIndex, Qt::AscendingOrder, false);
d->model->sort(logicalIndex, Qt::AscendingOrder, false);
} else {
d->horizontalHeader->setSortIndicator(logicalIndex, Qt::DescendingOrder, false);
d->model->sort(logicalIndex, Qt::DescendingOrder, false);
}
d->model->refresh();
//} else if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
} else if (d->model->hasFeature(AbstractTableModel::Sortable)) {
d->model->clearSort();
if (d->horizontalHeader->isSortIndicatorShown(logicalIndex)) {
if (d->horizontalHeader->sortIndicatorOrder(logicalIndex) == Qt::DescendingOrder) {
d->horizontalHeader->clearSortIndicators();
d->model->refresh();
} else {
if (d->horizontalHeader->sortIndicatorSections().count() > 1)
d->horizontalHeader->clearSortIndicators();
d->horizontalHeader->setSortIndicator(logicalIndex, Qt::DescendingOrder);
d->model->sort(logicalIndex, Qt::DescendingOrder);
}
} else {
if (d->horizontalHeader->sortIndicatorSections().count() > 1)
d->horizontalHeader->clearSortIndicators();
d->model->sort(logicalIndex, Qt::AscendingOrder);
d->horizontalHeader->setSortIndicator(logicalIndex, Qt::AscendingOrder);
}
d->model->refresh();
selectColumn(logicalIndex);
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.147 секунд. Запросов: 20.