如何使QSortFilterProxyModel更快

时间:2014-05-24 23:09:53

标签: c++ qt qsortfilterproxymodel

我在快速制作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 &regExp, 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;
}

0 个答案:

没有答案