Как получить список видимых QModelIndex в QAbstractItemView

Есть ли способ получить список видимых в данный момент элементов в QAbstractItemView? И, если возможно, получать какие-либо уведомления об изменении этого списка.

Upd: я спрашиваю именно про QAbstractItemView или QTreeView с непростым строением, а не про QTableView.

Upd2: я реализую древовидную модель с флажками. Я хочу следующее поведение (то же самое для проверки/снятия):

  • Если один из флажков отмечен - тогда все дочерние элементы должны быть проверены
  • Если все дочерние флажки отмечены, то родительский флажок также должен быть установлен. И то же самое для родителя родителя и так далее...

Состояние проверки отслеживается/изменяется внешним источником данных, поэтому мне нужен механизм для обновления всех измененных дочерних/родительских элементов. dataChanged сигнала мне недостаточно, потому что очень сложно построить список всех измененных QModelIndex для обновления. Да и не нужно, потому что все свежие данные будут браться из QAbstractItemModel::data.

Я нашел следующий грязный хак для обновления всех элементов: emit dataChanged( QModelIndex(), QModelIndex() );, но он не задокументирован для недопустимых индексов.

Итак, мне нужен способ заставить все видимые элементы перерисовывать их содержание со свежими данными.


person Dmitry Sazonov    schedule 04.04.2013    source источник


Ответы (4)


Вы можете получить верхнюю левую и нижнюю правую ячейку, позвонив:

tableview->indexAt(tableview->rect().topLeft())
tableview->indexAt(tableview->rect().bottomRight())

Чтобы получить уведомление об изменении, повторно реализуйте виртуальную функцию qabstractscrollarea.

scrollContentsBy

Эта функция вызывается при прокрутке окна просмотра. вызовите QTableView::scrollContentsBy, а затем сделайте все, что вам нужно.

person Min Lin    schedule 04.04.2013
comment
Я не спрашиваю о простом QTableView, мне все ясно... Я спрашиваю о пользовательском древовидном представлении с моим собственным делегатом элементов. Уведомлений прокрутки недостаточно, потому что они не охватывают события развертывания и свертывания. - person Dmitry Sazonov; 05.04.2013
comment
Вы по-прежнему можете использовать indexAt для получения индексов в области просмотра. И подключите сигналы расширения и свертывания прокрутки к слоту, который будет пересчитывать индексы. Я думаю, что если вы не хотите делать что-то грязное, например, перехватывать метод рисования, то подключение ко всем существующим сигналам, которые изменяют область просмотра, - это путь. - person Min Lin; 05.04.2013
comment
indexAt неприемлем, потому что я использую QTreeView, а некоторые элементы не подходят для всей строки. См. обновление исходного вопроса. - person Dmitry Sazonov; 05.04.2013
comment
rect().topLeft() по определению всегда (0,0). Для QTreeView visualRect для индекса по какой-то причине исключает значок треугольника развертывания/свертывания, поэтому visualRect().left() >= 20 в моем случае. Поэтому indexAt не должен работать. По какой-то причине это все еще работает ... но я бы скептически отнесся к тому, что это непреднамеренное поведение (или недокументированный особый случай). - person mxmlnkn; 22.08.2019

Для QTreeView список видимых элементов можно просмотреть следующим образом:

QTreeView& tv (yourTreeView);

// Get model index for first visible item
QModelIndex modelIndex = tv.indexAt(tv.rect().topLeft());

while (modelIndex.isValid())
{
    // do something with the item indexed by modelIndex
    ...
    // This navigates to the next visible item
    modelIndex = tv.indexBelow(modelIndex);
}
person Adrian W    schedule 13.03.2014
comment
Индекса в левом верхнем углу может не быть. Это зависит от реализации дополнений/делегатов стиля и других вещей. - person Dmitry Sazonov; 14.03.2014
comment
// Переход к следующему видимому элементу modelIndex = tv.indexBelow(modelIndex); Будет зацикливаться до конца дерева. Может быть, только здесь мы можем поставить еще одну проверку, если она находится в области tv.rect(), мы можем разорвать цикл или проверить ItemAt(index). & проверьте, если значение оси Y меньше, чем tv.tect.bottomLeft().y(), спасибо, разорвите цикл. - person NDestiny; 27.11.2015
comment
Чтобы быть более точным, indexBelow, похоже, обходит все развернутые элементы, а не только те, которые видны в окне просмотра. Кроме того, вместо сравнения с tv.rect(), я думаю, следует использовать tv.viewport.rect(), потому что он учитывает заголовок дерева/таблицы. Что касается проблемы indexAt(topLeft()), упомянутой @DmitrySazonov, я открыл проблему/вопрос здесь< /а>. - person mxmlnkn; 22.08.2019

Я думаю, что нет случаев, когда требуется список видимых элементов. В случае корректной реализации модели все элементы обновляются автоматически. Сложная часть реализации - заставить детей и родителей обновляться. Я написал следующий код:

bool TreeModel::setData( const QModelIndex &index, const QVariant &value, int role )
case Qt::CheckStateRole:
        {
            TreeItemList updateRangeList;  // Filled with items, in which all childred must be updated
            TreeItemList updateSingleList; // Filled with items, which must be updated
            item->setCheckState( value.toBool(), updateRangeList, updateSingleList ); // All magic there
            foreach ( TreeAbstractItem *i, updateRangeList )
            {
                const int nRows = i->rowCount();
                QModelIndex topLeft = indexForItem( i->m_childs[0] );
                QModelIndex bottomRight = indexForItem( i->m_childs[nRows - 1] );
                emit dataChanged( topLeft, bottomRight );
            }
            foreach ( TreeAbstractItem *i, updateSingleList )
            {
                QModelIndex updateIndex = indexForItem( i );
                emit dataChanged( updateIndex, updateIndex );
            }
        }
person Dmitry Sazonov    schedule 08.04.2013

я всегда обновляю весь QAbstractTableModel с помощью:

emit dataChanged(index(0, 0), index(rowCount(), columnCount()-1)); // update whole view
person roberto    schedule 01.08.2017
comment
emit dataChanged( QModelIndex{}, QModelIndex{} ); выглядит лучше и эффективнее. - person Dmitry Sazonov; 01.08.2017