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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] QTableView - видимые ячейки  (Прочитано 20147 раз)
Sky
Гость
« : Июль 07, 2010, 13:16 »

Доброго времени суток!

Мне необходимо выводить большой объем данных в таблице. Для этого унаследовал модель от QAbstractTableModel. Для отображения использую QTableView.
Так вот сам вопрос: как мне определить какой диапазон строк сейчас виден пользователю и как отловить событие, при котором этот диапазон меняется?
Поиск результатов не дал.  Грустный

Заранее большое спасибо.


« Последнее редактирование: Август 02, 2010, 13:13 от Sky » Записан
SABROG
Гость
« Ответ #1 : Июль 07, 2010, 15:18 »

Посмотри этот пример

http://doc.qt.nokia.com/latest/tools-contiguouscache.html

Логика тут такая, если ячейка становится видимой, то у нее идет запрос Qt::DisplayRole.
Код
C++ (Qt)
QVariant RandomListModel::data(const QModelIndex &index, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();
...
 
« Последнее редактирование: Июль 07, 2010, 16:00 от SABROG » Записан
Sky
Гость
« Ответ #2 : Июль 07, 2010, 16:20 »

Т.е. только вручную сохранять в data() максимальное/минимальное значения для строк?
И событие изменения диапазона видимых ячеек собирать из события прокрутки и изменения размера области просмотра?
К этому уже пришел, но такое чувство, что неправильно это. Неужто нет более элегантного способа?

upd:
Тут еще дело в том, что данные у меня извлекаются из базы в отдельном потоке, т. е. внешне это выглядит так, что пользователь прокрутил (без тормозов) до нужного места, а с небольшим запаздыванием в ячейках появляются данные.
При этом не хотелось бы читать данные из базы по строчке (нечто подобное в Вашем примере), а хотелось бы по событию изменения диапазона видимых строк прочитать недостающий блок данных сразу целиком.
Видимо придется по событиям прокрутки/изменения размера вычислять диапазон строк, используя номер первой строки, высоту строк и высоту области просмотра...
« Последнее редактирование: Июль 07, 2010, 16:43 от Sky » Записан
DmP
Гость
« Ответ #3 : Июль 07, 2010, 16:49 »

Так вот сам вопрос: как мне определить какой диапазон строк сейчас виден пользователю и как отловить событие, при котором этот диапазон меняется?
Как вариант унаследовать QTableView и переопределить функции updateGeometries() и scrollContentsBy(), в них можно определять первую и последнюю видимую строку через ф-ции verticalHeader()->logicalIndexAt() и viewport()->geometry().
Записан
SABROG
Гость
« Ответ #4 : Июль 08, 2010, 00:50 »

При этом не хотелось бы читать данные из базы по строчке (нечто подобное в Вашем примере), а хотелось бы по событию изменения диапазона видимых строк прочитать недостающий блок данных сразу целиком.
data() c ролью Qt::DisplayRole вызывается тогда, когда элемент становится видимым на вьюпорте. Если у тебя размер вьюпорта вмещает 2 итема, а в модели 100000 итемов, то data() будет вызван 2 раза. Когда пользователь начинает прокручивать таблицу, то на каждый появляющийся итем вызывается data() c Qt::DisplayRole.

Предположим, что у тебя в базе 1 миллион записей. Перед тем как заполнить представление ты прочитал записи с Primary Key 0-100 (100 записей):

Код
SQL
SELECT * FROM mytable WHERE KEY BETWEEN 0 AND 100 ORDER BY KEY ASC

и поместил их в QContiguousCache. Модель забирает эти 100 записей из кэша и отображает на представлении. Собственно массовый (не построчный, как тебе и нужно) забор данных идет в этих строках:

Код
C++ (Qt)
else while (row > m_rows.lastIndex())
            m_rows.append(fetchRow(m_rows.lastIndex()+1));
 

Только у троллей while, а у тебя обычный SELECT к базе должен быть.
Записан
daimon
Гость
« Ответ #5 : Июль 20, 2010, 09:59 »

А в модели так и возвращать, что строк где-то миллионы или тысячи - много (rowCount)?
Записан
Pink_Panter
Гость
« Ответ #6 : Июль 22, 2010, 13:20 »

Пытаюсь сделать так, как описано в этой теме.

По непонятной для меня причине в моей модели data() c ролью Qt::DisplayRole вызывается пару-тройку раз для всех записей и только после этого для записей из вьюпорта. При этом столбцы запрашиваются только те, которые попадают во вьюпорт.

Как бы мне отучить потомка QTableView запрашивать сразу все строки по каждому чиху?
Записан
Pink_Panter
Гость
« Ответ #7 : Июль 23, 2010, 20:55 »

Разобрался я со своей проблемой.
Сдуру у QTableView включил установку размеров строк и столбцов по содержимому.
Вот оно и гоняло data модели в хвост и в гриву. Причем сволочь запрашивало не только HintSize, но и сами данные.
Записан
SABROG
Гость
« Ответ #8 : Июль 24, 2010, 12:31 »

Разобрался я со своей проблемой.
Сдуру у QTableView включил установку размеров строк и столбцов по содержимому.
Вот оно и гоняло data модели в хвост и в гриву. Причем сволочь запрашивало не только HintSize, но и сами данные.

Логично, чтобы подогнать размер итема под размер данных их сначала нужно получить. Хотя если у тебя есть готовый пример я бы отписал троллям предложение о добавлении какого-нибудь аттрибута, который бы позволял подгонять итемы под размер только для видимой части (на лету).
Записан
Pink_Panter
Гость
« Ответ #9 : Июль 25, 2010, 13:19 »

Тут про готовый пример тяжело сказать. Если очень понадобится - сделаю. если есть возможность донести до троллей...
Насколько я понимаю MVC: функция data у модели вызывается вьювером с разными ролями для разных задач.
Для запроса размеров есть специальная роль HintSize или что-то похожее. (Пишу из дома ассистент не под рукой).
а для запроса значения - вызывается DisplayRole  или EditRole.
С чем я столкнулся:
Для быстрой работы с весьма большой таблицей БД и для реализации нужного мне доп.функционала
я как в этой теме тобой рекомендовано (Кстати спасибо за очень полезный совет) реализовал потомка QAbstractTableModel в котором использовал QContiguousCache. Функцию data реализовал более полно чем в примере у троллей. С разбором ролей и возвратом соответствующих значений. Сейчас все работает просто превосходно. (если не включать авторазмер по содержимому у QTableView)
Желаемые размеры колонок я легко получаю одним запросом и храня их в внутренних переменных могу не напрягаясь отдавать их хоть миллионы раз.
А вот запрос некешированных данных занимает довольно много времени. (Собственно кэш для того и делал, что бы не тащить сразу всю таблицу в память, а только по мере необходимости).
Собственно вопрос к троллям:
Зачем? запрашивать сами данные? если нужный мне размер под эти данные модель может сказать, или даже уже сказала?
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #10 : Июль 25, 2010, 13:49 »

если речь идёт о геометрическом размере ячейки, то этот размер определяется делегатом, функцией sizeHint(), как и у всех виджетов. Представление не обращается за размером к модели, оно обращается к делегату.

Qt::SizeHintRole используется только в функции Model::headerData(...) для определения размеров заголовков
« Последнее редактирование: Июль 25, 2010, 13:53 от lit-uriy » Записан

Юра.
Pink_Panter
Гость
« Ответ #11 : Июль 25, 2010, 21:30 »

Возможно. Но вроде отладчик у меня регистрировал Qt::SizeHintRole в функции data.
Хотя это уже не важно. Моя задача успешно решена. А о методологии пусть у троллей голова болит. Я на хайлевел не претендую, пользуюсь тем, что есть.
Записан
Sky
Гость
« Ответ #12 : Август 02, 2010, 11:09 »

Меня тут временно на другую задачу перебрасывали, так что не мог отписаться.

DmP

Код:
else while (row > m_rows.lastIndex())
             m_rows.append(fetchRow(m_rows.lastIndex()+1));
Это ведь вызывается в data() модели? Тогда при прокрутке будет притормаживать, пока не загрузится часть таблицы из базы. Или нет?

Сейчас сделал так:
При изменении размера или при прокрутке QTableView стартует в отдельном потоке чтение необходимых строк из БД (при этом уже загруженные строки не грузятся). При этом передается первая строка (получена по сигналу valueChanged(int) QTableModel::verticalScrollBar()) и последняя (QTableView::rowAt(height()-1)).
В принципе все работает, кроме того, что при прокрутке в самый низ таблицы rowAt(height()-1) возвращает -1. При прокрутке вверх на 3 строки возвращается нормальное значение (при любом размере таблицы).
Ну и само по себе rowAt(height()-1) как-то криво выглядит.
Записан
DmP
Гость
« Ответ #13 : Август 02, 2010, 12:09 »

Сейчас сделал так:
В принципе все работает, кроме того, что при прокрутке в самый низ таблицы rowAt(height()-1) возвращает -1.
Это нормально, у тролей при определении последней строки в таблице если получается -1, то берется максимальный номер строки, типа model()->rowCount() - 1. Только у них от высоты не отнимается 1, просто rowAt(viewport()->height())
Записан
Sky
Гость
« Ответ #14 : Август 02, 2010, 12:16 »

Это нормально, у тролей при определении последней строки в таблице если получается -1, то берется максимальный номер строки, типа model()->rowCount() - 1. Только у них от высоты не отнимается 1, просто rowAt(viewport()->height())

Спасибо!
Т. е. такой способ определения последней строки является правильным?
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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