我在快速制作QSortFilterProxyModel(连接到sqlite数据库)时遇到问题。当数据库接近空时,一切都很好,但随着行的增加,模型开始变得非常慢。我读了here您可以缓存结果以加快搜索速度,但它似乎并不适合我。任何人都可以建议并解释我如何更快地进行搜索的方法吗?
下面的代码显示了我如何重新实现该类。请注意,我必须重新实现QSortFilterProxyModel :: filterAcceptsRow()函数,以允许代理模型同时过滤多个列(我从其他地方获取的代码...... heeeheeeheee)。
CustomProxyModel::CustomProxyModel(QObject *parent) :
flag(Default),
QSortFilterProxyModel(parent)
{
}
CustomProxyModel::CustomProxyModel(FilterFlag flag, QObject *parent) :
flag(flag),
QSortFilterProxyModel(parent)
{
}
void CustomProxyModel::setFilterKeyColumns(const QList<qint32> &filterColumns) {
m_columnPatterns.clear();
foreach(qint32 column, filterColumns) {
m_columnPatterns.insert(column, qMakePair(QString(), Default));
}
}
void CustomProxyModel::addFilterFixedString(qint32 column, const QString &pattern, FilterFlag flag) {
if(!m_columnPatterns.contains(column))
return;
m_columnPatterns[column] = qMakePair(pattern, flag);
recalculateFilter(pattern);
invalidateFilter();
}
void CustomProxyModel::setFilterKeyColumn(int column) {
m_columnPatterns.clear();
QSortFilterProxyModel::setFilterKeyColumn(column);
}
void CustomProxyModel::setFilterFixedString(const QString &pattern, FilterFlag flag) {
filterFixedString = pattern;
setFilterFlag(flag);
recalculateFilter(pattern);
invalidateFilter();
}
void CustomProxyModel::setFilterRegExp(const QString &pattern, FilterFlag flag) {
setFilterFlag(flag);
QSortFilterProxyModel::setFilterRegExp(pattern);
}
void CustomProxyModel::setFilterRegExp(const QRegExp ®Exp, FilterFlag flag) {
setFilterFlag(flag);
QSortFilterProxyModel::setFilterRegExp(regExp);
}
bool CustomProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
if(m_lastFilter.isEmpty() || m_cache.contains(source_row))
return true;
if(!m_columnPatterns.isEmpty())
return filterStrings(source_row, source_parent);
switch(flag) {
case Int:
return filterInt(source_row, source_parent);
break;
case Double:
return filterDouble(source_row, source_parent);
break;
case LongLong:
return filterLongLong(source_row, source_parent);
break;
case DateTime:
return filterDateTime(source_row, source_parent);
break;
case String:
case Default:
return filterString(source_row, source_parent);
break;
default:
break;
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
bool CustomProxyModel::filterStrings(int source_row, const QModelIndex &source_parent) const {
if(m_columnPatterns.isEmpty())
return true;
bool ret = false;
for(int i = 0; i < m_columnPatterns.count(); i++)
{
int column = m_columnPatterns.keys().at(i);
QString pattern = m_columnPatterns.value(column).first;
FilterFlag flag = m_columnPatterns.value(column).second;
if((flag == String) || (flag == Default))
ret = filterString(source_row, source_parent, column, pattern);
else if(flag == Int)
ret = filterInt(source_row, source_parent, column, pattern);
else if(flag == Double)
ret = filterDouble(source_row, source_parent, column, pattern);
else if(flag == LongLong)
ret = filterLongLong(source_row, source_parent, column, pattern);
else if(flag == DateTime)
ret = filterDateTime(source_row, source_parent, column, pattern);
if(!ret)
return ret;
}
return ret;
}
bool CustomProxyModel::filterString(int source_row, const QModelIndex &source_parent, int column, QString pattern) const {
if(column < 0)
column = filterKeyColumn();
if(pattern.isEmpty())
pattern = filterFixedString;
QModelIndex index = sourceModel()->index(source_row, column, source_parent);
QString string = index.data(Qt::DisplayRole).toString();
if(pattern.isEmpty())
return true;
if(string.contains(pattern, Qt::CaseInsensitive))
return true;
return false;
}
bool CustomProxyModel::filterInt(int source_row, const QModelIndex &source_parent, int column, QString pattern) const {
if(column < 0)
column = filterKeyColumn();
if(pattern.isEmpty())
pattern = filterFixedString;
QModelIndex index = sourceModel()->index(source_row, column, source_parent);
bool ok = true;
int id = sourceModel()->data(index, Qt::EditRole).toInt(&ok);
if(!id)
return true;
if(ok) {
if(id == pattern.toInt())
return true;
else
return false;
}
return false;
}
bool CustomProxyModel::filterDouble(int source_row, const QModelIndex &source_parent, int column, QString pattern) const {
if(column < 0)
column = filterKeyColumn();
if(pattern.isEmpty())
pattern = filterFixedString;
QModelIndex index = sourceModel()->index(source_row, column, source_parent);
return true;
}
bool CustomProxyModel::filterLongLong(int source_row, const QModelIndex &source_parent, int column, QString pattern) const {
if(column < 0)
column = filterKeyColumn();
if(pattern.isEmpty())
pattern = filterFixedString;
QModelIndex index = sourceModel()->index(source_row, column, source_parent);
bool ok;
qulonglong id = sourceModel()->data(index, Qt::DisplayRole).toLongLong(&ok);
if(!ok)
return false;
qulonglong filterValue = pattern.toLongLong(&ok);
if(pattern.isEmpty())
return true;
if(!ok)
return false;
if(!filterValue)
return true;
if(id == filterValue)
return true;
return false;
}
bool CustomProxyModel::filterDateTime(int source_row, const QModelIndex &source_parent, int column, QString pattern) const {
if(column < 0)
column = filterKeyColumn();
if(pattern.isEmpty())
pattern = filterFixedString;
QModelIndex index = sourceModel()->index(source_row, column, source_parent);
QString dateTimeString = sourceModel()->data(index, Qt::EditRole).toString();
QDateTime dateTime = QDateTime::fromString(dateTimeString, DatabaseManager::getDateTimeFormat());
return dateTimeInRange(dateTime);
}
bool CustomProxyModel::dateTimeInRange(const QDateTime &dateTime) const {
return (!minDateTime.isValid() || dateTime > minDateTime)
&& (!maxDateTime.isValid() || dateTime < maxDateTime);
}
void CustomProxyModel::setFilterMinDateTime(const QDateTime &dateTime)
{
minDateTime = dateTime;
invalidateFilter();
}
void CustomProxyModel::setFilterMaxDateTime(const QDateTime &dateTime)
{
maxDateTime = dateTime;
invalidateFilter();
}
void CustomProxyModel::recalculateFilter(const QString &str) {
if(!m_lastFilter.isEmpty() && str.contains(m_lastFilter)) {
// update the cache by removing items
for(QSet<int>::iterator iter = m_cache.begin(); iter!=m_cache.end();) {
QModelIndex idx = sourceModel()->index(*iter, filterKeyColumn());
if(!idx.data().toString().contains(str))
m_cache.erase(iter); // remove from cache
else
++iter;
}
}
else if(!m_lastFilter.isEmpty() && m_lastFilter.contains(str)) {
// update cache by adding items
for(int i = 0; i < sourceModel()->rowCount(); ++i) {
if(m_cache.contains(i))
continue;
QModelIndex idx = sourceModel()->index(i, filterKeyColumn());
if(idx.data().toString().contains(str))
m_cache.insert(i);
}
}
else {
// recompute everything
m_cache.clear();
if(!str.isEmpty()) {
for(int i = 0; i < sourceModel()->rowCount(); ++i) {
QModelIndex idx = sourceModel()->index(i, filterKeyColumn());
if(idx.data().toString().contains(str))
m_cache.insert(i);
}
}
}
m_lastFilter = str;
//invalidateFilter();
}
void CustomProxyModel::setFilterFlag(FilterFlag flag) {
this->flag = flag;
}
CustomProxyModel::FilterFlag CustomProxyModel::getFilterFlag() const {
return flag;
}