C++ (Qt)// Первоночально при помощи запроса заполняем только idList данными первичного ключа.//mutable QCache<const QString,CashData> cashList;// cashData вызываеться при изменение положения вертикального скролл бара у QlistView.void MyListModel::cashData(int from, int to){ // Сохраняем в кеше информацию // from и to это номера строк в поле видимости // Загружаем информацию для строк с from по to // и сохраняем её в cashList; // (загрузка сразу нескольких значений из БД происходит быстрее, чем выгрузка их по отдельности) QStringList list; // Не имеет смысла запоминать больше максимального ограничения на cashList if(to - from > cashList.maxCost()) to = from + cashList.maxCost(); for(int row = from; row <= to ;++row) { const QString* id = & idList.at(row); if(!cashList.contains(*id)) list<<"'" + *id + "'"; } query.exec("SELECT id, ... , WHERE id IN (" + list.join(",") + ")") + QString(" LIMIT %1 ").arg(to - from)); while(query.next()) cashList.insert(query.value(0).toString(),new CashData(query.value(1).toString(),query.value(2).toBool()));} QVariant MyListModel::data(const QModelIndex& index, int role) const{ switch(role) { case Qt::SizeHintRole:return size_hint; case Qt::DisplayRole: case Qt::ToolTipRole: { const QString* id = & idList.at(row); if(id->isNull()) return QVariant(tr("загрузка...")); if(cashList.contains(*id))//если в кеше уже есть текст для данной строчки выводим его return cashList.object(*id)->display_text; query.exec("...запрос... WHERE id ='" + *id + "' LIMIT 1"); query.first(); QString display_text = query.value(0).toString() + query.value(1).toString() +...; cashList.insert(*id,new CashData(display_text, query.value(1).toBool())); return display_text; } case Qt::DecorationRole: return QIcon(":icon"); case Qt::UserRole: return idList.at(row); default: return QVariant(); }}