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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: медленная сортировка и фильтрация данных в TableView  (Прочитано 5915 раз)
nono
Гость
« : Март 31, 2015, 21:34 »

Для реализации таблицы использую элемент TableView. Сама модель реализована на базе QSqlQueryModel
Вот часть кода модели
Код:
ModelDevices::ModelDevices(QSqlDatabase &db, QObject *parent): query(db), QSqlQueryModel(parent)
{
    int index(1);
    roles[Qt::UserRole + index++] += "device_id";
    roles[Qt::UserRole + index++] += "section";
    roles[Qt::UserRole + index++] += "division";
    roles[Qt::UserRole + index++] += "power_center";
    roles[Qt::UserRole + index++] += "group_name";
    roles[Qt::UserRole + index++] += "net_address";
    roles[Qt::UserRole + index++] += "personal_account";
    roles[Qt::UserRole + index++] += "payment_code";
    roles[Qt::UserRole + index++] += "accounting_type";
    roles[Qt::UserRole + index++] += "settlement";
    roles[Qt::UserRole + index++] += "street";
    roles[Qt::UserRole + index++] += "house";
    roles[Qt::UserRole + index++] += "consumer_name";
    roles[Qt::UserRole + index++] += "serial_number";
    roles[Qt::UserRole + index++] += "repeater";
    roles[Qt::UserRole + index++] += "coefficient";
    roles[Qt::UserRole + index++] += "device_type";
    roles[Qt::UserRole + index++] += "ra_id";
    roles[Qt::UserRole + index++] += "gateway_number";
    roles[Qt::UserRole + index++] += "device_status";
    roles[Qt::UserRole + index++] += "askue";
    roles[Qt::UserRole + index++] += "note";
    roles[Qt::UserRole + index++] += "device_removed";
    roles[Qt::UserRole + index++] += "object_id";
}
//==============================================
QVariant ModelDevices::data(const QModelIndex &item, int role) const
{
    QVariant value;
    if (role < Qt::UserRole) {
        value = QSqlQueryModel::data(item, role);
    } else {
        int columnIndex = role - Qt::UserRole - 1;
        QModelIndex modelIndex = this->index(item.row(), columnIndex);
        value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
    }
    return value;
}
//==============================================
QHash<int, QByteArray> ModelDevices::roleNames() const
{
    return roles;
}
//==============================================
Для осуществления сортировки использую модель на базе QSortFilterProxyModel
Вот код
Код:
SortFilterProxyModel::SortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_complete(false)
{
    connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()));
    connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()));
}

int SortFilterProxyModel::count() const
{
    return rowCount();
}

QObject *SortFilterProxyModel::source() const
{
    return sourceModel();
}

void SortFilterProxyModel::setSource(QObject *source)
{
    setSourceModel(qobject_cast<QAbstractItemModel *>(source));
}

QByteArray SortFilterProxyModel::sortRole() const
{
    return m_sortRole;
}

void SortFilterProxyModel::setSortRole(const QByteArray &role)
{
    if (m_sortRole != role) {
        m_sortRole = role;
        if (m_complete)
            QSortFilterProxyModel::setSortRole(roleKey(role));
    }
}

void SortFilterProxyModel::setSortOrder(Qt::SortOrder order)
{
    QSortFilterProxyModel::sort(0, order);
}

QByteArray SortFilterProxyModel::filterRole() const
{
    return m_filterRole;
}

void SortFilterProxyModel::setFilterRole(const QByteArray &role)
{
    if (m_filterRole != role) {
        m_filterRole = role;
        if (m_complete)
            QSortFilterProxyModel::setFilterRole(roleKey(role));
    }
}

QString SortFilterProxyModel::filterString() const
{
    return filterRegExp().pattern();
}

void SortFilterProxyModel::setFilterString(const QString &filter)
{
    setFilterRegExp(QRegExp(filter, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax())));
}

SortFilterProxyModel::FilterSyntax SortFilterProxyModel::filterSyntax() const
{
    return static_cast<FilterSyntax>(filterRegExp().patternSyntax());
}

void SortFilterProxyModel::setFilterSyntax(SortFilterProxyModel::FilterSyntax syntax)
{
    setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(syntax)));
}

QJSValue SortFilterProxyModel::get(int idx) const
{
    QJSEngine *engine = qmlEngine(this);
    QJSValue value = engine->newObject();
    if (idx >= 0 && idx < count()) {
        QHash<int, QByteArray> roles = roleNames();
        QHashIterator<int, QByteArray> it(roles);
        while (it.hasNext()) {
            it.next();
            value.setProperty(QString::fromUtf8(it.value()), data(index(idx, 0), it.key()).toString());
        }
    }
    return value;
}

void SortFilterProxyModel::classBegin()
{
}

void SortFilterProxyModel::componentComplete()
{
    m_complete = true;
    if (!m_sortRole.isEmpty())
        QSortFilterProxyModel::setSortRole(roleKey(m_sortRole));
    if (!m_filterRole.isEmpty())
        QSortFilterProxyModel::setFilterRole(roleKey(m_filterRole));
}

int SortFilterProxyModel::roleKey(const QByteArray &role) const
{
    QHash<int, QByteArray> roles = roleNames();
    QHashIterator<int, QByteArray> it(roles);
    while (it.hasNext()) {
        it.next();
        if (it.value() == role)
            return it.key();
    }
    return -1;
}

QHash<int, QByteArray> SortFilterProxyModel::roleNames() const
{
    if (QAbstractItemModel *source = sourceModel())
        return source->roleNames();
    return QHash<int, QByteArray>();
}

bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
    QRegExp rx = filterRegExp();
    if (rx.isEmpty())
        return true;
    QAbstractItemModel *model = sourceModel();
    if (filterRole().isEmpty()) {
        QHash<int, QByteArray> roles = roleNames();
        QHashIterator<int, QByteArray> it(roles);
        while (it.hasNext()) {
            it.next();
            QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
            QString key = model->data(sourceIndex, it.key()).toString();
            if (key.contains(rx))
                return true;
        }
        return false;
    }
    QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
    if (!sourceIndex.isValid())
        return true;
    QString key = model->data(sourceIndex, roleKey(filterRole())).toString();
    return key.contains(rx);
}
Вот код передачи объектов в форму qml
Код:
engine = new QQmlApplicationEngine(this);
    qmlRegisterType<SortFilterProxyModel>("org.qtproject.example", 1, 0, "SortFilterProxyModel");
    engine->load(QUrl("qrc:///Ui/MainWindow"));
    engine->rootContext()->setContextProperty("ram", this);
    engine->rootContext()->setContextProperty("modelGroups", modelGroups);
    engine->rootContext()->setContextProperty("modelObjects", modelObjects);
    engine->rootContext()->setContextProperty("modelDevices", modelDevices);
А вот код настройки прокси модели
Код:
  // Настройка прокси модели
    SortFilterProxyModel {
        id: proxyModelDevices
        source: modelDevices

        sortOrder: viewListDevices.sortIndicatorOrder
        //sortCaseSensitivity: Qt.CaseInsensitive
        sortRole: viewListDevices.getColumn(viewListDevices.sortIndicatorColumn).role

        filterString: textSearch.text
        filterSyntax: SortFilterProxyModel.Wildcard
        filterCaseSensitivity: Qt.CaseInsensitive
    }
Проблема заключается в сортировке и фильтре данных. Данные процессы происходят очень медленно, учитывая что в базе хранится несколько десятков тысяч записей. При этом С-шная реализация на базе QTableView с теми же самыми моделями производит фильтрацию и сортировку достаточно быстро. Как можно ускорить все это дело в qml?
« Последнее редактирование: Март 31, 2015, 21:41 от nono » Записан
Отражение луны
Гость
« Ответ #1 : Март 31, 2015, 22:26 »

Я сразу скажу, что не знаю с++ и, следовательно, не знаю как работает проксимодель. Поэтому моё предположение будет основано на предположениях, как ни парадоксально. ListView, на котором основан TableView, отрисовывает только видимые элементы. Скорее всего при загрузке всего списка тормозов Вы не наблюдаете. А выглядит cbnefwbz так, будто при поиске или фильтрации удаление несоответствующих критериям поиска  элементов приводит к тому, что видимыми становятся ранее скрытые элементы, а именно каждый(в т.ч. удаляемые) из них, и происходит это до тех пор, пока прошедшие сортировку элементы полностью не заполнят собой табличное пространство. И QML старательно создает, разрушает и пытается отрисовать все то, что на самом деле в итоге будет отфильтровано. В таком случае Вы, возможно, оповещаете таблицу об изменении при каждом удалении отфильтрованного элемента, а не когда фильтрация отработала полностью.
« Последнее редактирование: Март 31, 2015, 22:42 от Отражение луны » Записан
nono
Гость
« Ответ #2 : Март 31, 2015, 23:00 »

Я сразу скажу, что не знаю с++ и, следовательно, не знаю как работает проксимодель. Поэтому моё предположение будет основано на предположениях, как ни парадоксально. ListView, на котором основан TableView, отрисовывает только видимые элементы. Скорее всего при загрузке всего списка тормозов Вы не наблюдаете. А выглядит cbnefwbz так, будто при поиске или фильтрации удаление несоответствующих критериям поиска  элементов приводит к тому, что видимыми становятся ранее скрытые элементы, а именно каждый(в т.ч. удаляемые) из них, и происходит это до тех пор, пока прошедшие сортировку элементы полностью не заполнят собой табличное пространство. И QML старательно создает, разрушает и пытается отрисовать все то, что на самом деле в итоге будет отфильтровано. В таком случае Вы, возможно, оповещаете таблицу об изменении при каждом удалении отфильтрованного элемента, а не когда фильтрация отработала полностью.
У меня были уже такие предположения, потому что я уже все перепробовал.
Тогда возникает другой вопрос...как TableView заставить производить отрисовку, только после окончания фильтрации или сортировки модели?
Записан
Отражение луны
Гость
« Ответ #3 : Апрель 01, 2015, 03:14 »

Полагаю, что адекватного способа нет (из неадекватных я бы предолжил попробовать изменить размеры на нулевые). У меня была похожая ситуация, и даже если компонент невиден почему-то делегаты все равно создавались. Если прокрутить невидимый список (listview) яваскриптом - аналогично. Поэтому можно сделать вывод, что дело даже не в отрисовке самой , большую часть времени занимает именно создание и разрушение делегатов, при этом qml даже может давать течь (наблюдал на 5.2.х). Имхо стоит попробовать:
1) полную очистку модели и заполнение её заново
2) на время выполнения фильтрации выставлять model = null
И то и другое, естественно, вернет список в начало и полностью пересоздаст строки таблицы.
« Последнее редактирование: Апрель 01, 2015, 03:16 от Отражение луны » Записан
nono
Гость
« Ответ #4 : Апрель 01, 2015, 21:34 »

1) полную очистку модели и заполнение её заново
2) на время выполнения фильтрации выставлять model = null
И то и другое, естественно, вернет список в начало и полностью пересоздаст строки таблицы.
Да чет не очень получается....Короче я пришел к выводу что для реализации серьезных проектов qml еще сыроват...лучше использовать старые проверенные виджиты
Записан
Отражение луны
Гость
« Ответ #5 : Апрель 02, 2015, 02:22 »

Могу лишь сказать, что у нас в проекте тоже QSqlQueryModel (но без qsortfilterproxymodel), фильтрация и сортировка осуществляется запросами, и отклик на поиск моментальный (~200 милисекунд максимум на самом слабом железе) при отображении ответа на ~5 к строк. Потому склонен думать, что проблема в чем-то еще.
Записан
nono
Гость
« Ответ #6 : Апрель 02, 2015, 21:21 »

Могу лишь сказать, что у нас в проекте тоже QSqlQueryModel (но без qsortfilterproxymodel), фильтрация и сортировка осуществляется запросами, и отклик на поиск моментальный (~200 милисекунд максимум на самом слабом железе) при отображении ответа на ~5 к строк. Потому склонен думать, что проблема в чем-то еще.
Такой вариант меня бы устроил если бы не больше кол-во подключений к базе данных....суть приложения следующая есть куча серверов независимых друг от друга порядка 60.....на них ведутся базы....доступ на прямую к базе у меня нет, через командную строку я могу выгрузить необходимы данные в отчет....я сделал модуль, который устанавливается на сервере и по команде выгружает нужный отчет, команды этому модулю посылает клиент, он же и получает отчет (все происходит по сети)....дальше этот клиент должен предоставлять интерфейс работы с этими данными и выгрузки определенных отчетов....на нем то у меня и не получается ускорить сортировку.....а запросы при сортировке я не использую потому, что обращения к серверам у меня происходит в многопоточном режиме, соответственно полученные данные и запись их в базу тоже в многопоточном режиме, для этого я открываю сразу нескольких подключений с одного клиента (с учетом основного до 30 одновременных подключений и транзакций).....как бы все хорошо, но клиент не один, количество соединений соответственно возрастает в разы...и по этому я стараюсь лишний раз к базе не тыкаться...пришел к решению прокси модели
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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