Давайте немножко копнем вглубь Qt (что то слишком часто мне приходится это делать в последнее время). Класс QHeaderViewPrivate (приватная реализация QHeaderView) имеет два приватных слота _q_layoutAboutToBeChanged() и _q_layoutChanged(). Как несложно догадаться из их названия эти слоты нужны, чтобы обрабатывать ситуации, в которых модель, подключенная к хедеру, тем или иным образом меняет местами свои индексы (как правило это банальная сортировка) - первый слот срабатывает перед началом сортировки, второй - после. Взглянув на эти слоты, нетрудно заметить, что они предназначены для работы в паре, как и все слоты-обработчики парных сигналов "до-после". Первый заполняет заполняет список persistent-индексов persistentHiddenSections, второй обрабатывает его и очищает. Вроде бы все логично.
На практике я увидел другую картину. Вызов метода сортировки модели обычного QTreeView (а QTreeView как мы с вами знаем имеет лишь один хедер - горизонтальный) привел к вызову лишь одного приватного слота хедера _q_layoutAboutToBeChanged(). Парный слот _q_layoutChanged() вызван не был
. Отыскать кто отламывает слот от сигнала было нетрудно. Вот это место
void QTreeView::setModel(QAbstractItemModel *model)
{
Q_D(QTreeView);
if (model == d->model)
return;
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(rowsRemoved(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
}
if (d->selectionModel) { // support row editing
disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
d->model, SLOT(submit()));
disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(rowsRemoved(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
}
d->viewItems.clear();
d->expandedIndexes.clear();
d->hiddenIndexes.clear();
d->header->setModel(model);
QAbstractItemView::setModel(model);
// QAbstractItemView connects to a private slot
disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
!!!!!!!
// do header layout after the tree
disconnect(d->model, SIGNAL(layoutChanged()),
d->header, SLOT(_q_layoutChanged()));
!!!!!!!
// QTreeView has a public slot for this
connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(rowsRemoved(QModelIndex,int,int)));
connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset()));
if (d->sortingEnabled)
d->_q_sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
}
Комментарий к этому дисконнекту меня конечно дюже порадовал. Из него следует, что дисконнект сделан для изменения порядка вызова слотов (чтобы хедер вызвал свой слот после вызова слота самого дерева), но тогда где повторный коннект
.
В итоге получаем, что при многократной сортировке модели список persistent-индексов спрятанных секций persistentHiddenSections будет набиваться данными, а очищен он так и не будет.
А теперь представьте следующую цепочку вызовов:
1. Прячем все столбцы хедера.
2. Вызываем метод сортировки модели. Все столбцы попадают в список persistentHiddenSections и там остаются.
3. Отображаем все или некоторые столбцы хедера.
4. Вызываю собственный метод модели, который меняет строки (не столбцы, а именно строки!!!) местами с помощью методов beginMoveRows() и endMoveRows(). Вызов endMoveRows() приводит к вызову невызванного слота хедера _q_layoutChanged() и ... правильно, этот слот скрывает все столбцы, т. к. все они до сих пор содержаться в persistentHiddenSections.
Кстати говоря, beginMoveRows() тоже не приводит к вызову _q_layoutAboutToBeChanged(), т.к. это горизонтальный хедер. То есть в этом случае из пары слотов вызовется теперь только второй. Но это как раз не является критичным, т.к. если список persistentHiddenSections пуст, никаких деструктивных действий слот с хедером не производит.
Получается, что изменение порядка строк модели приводит к скрытию всех столбцов хедера, что меня крайне удивило. Посмотрел на гите - реализация метода QTreeView::setModel() не менялась со времен царя Гороха. Сижу и думаю то ли я что то не доглядел, то ли это прикол у кутешников такой. Какой смысл специально отрывать парный слот хедера ума не приложу. Может вы мне поясните?