Название: QSortFilterProxyModel для древовидной модели
Отправлено: Странник от Декабрь 05, 2011, 15:23
имеется кастомная древовидная модель, унаследованная от QAbstractItemModel. для сортировки и фильтрации предполагалось использовать QSortFilterProxyModel, но обнаружились грабли - сортировка работает по всему дереву, а фильтрация - только для элементов первого уровня (с родительским индексом QModelIndex()). так оно и задумано или криво реализована кастомная модель?
Название: Re: QSortFilterProxyModel для древовидной модели
Отправлено: _OLEGator_ от Декабрь 05, 2011, 15:32
Криво реализовал. Дай код посмотреть.
Название: Re: QSortFilterProxyModel для древовидной модели
Отправлено: Странник от Декабрь 10, 2011, 13:44
в самом деле, если перед setFilterRegExp делаю резет исходной модели, все работает нормально. спасибо, решил проблему. но возникла новая беда. есть функция, которая делает примерно следующее (на самом деле алгоритм сложнее, но к вопросу это не относится): void find(QAbstractItemView *itemView, const QString &text) { QAbstractItemModel *model = itemView->model(); QModelIndexList match = model->match(model->index(0, 0), Qt::DisplayRole, text, 1, Qt::MatchWrap | Qt::MatchRecursive | Qt::MatchStartsWith);
if (!match.isEmpty()) itemView->setCurrentIndex(match.first()); }
если я делаю: MyCustomModel *myCustomModel = new MyCustomModel(this); QTreeView = new QTreeView(this); treeView->setModel(myCustomModel); find(treeView, text); нужная строка находится и выделяется, дерево до нее разворачивается. если же через прокси модель: MyCustomModel *myCustomModel = new MyCustomModel(this); QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(myCustomModel); QTreeView = new QTreeView(this); treeView->setModel(proxyModel); find(treeView, text); строка находится (match возвращает верный индекс), но дерево не разворачивается до элемента, определенного через setCurrentIndex. при этом currentIndex возвращает верный индекс. какие-то тонкости работы с индексами прокси модели или просто баг?
Название: Re: QSortFilterProxyModel для древовидной модели
Отправлено: Carobey от Февраль 02, 2012, 19:33
Добрый день. Возникла аналогичная проблема! Попробовал как Вы написали: QRegExp regExp(arg1, Qt::CaseInsensitive); proxy->sourceModel()->reset_(); proxy->setFilterRegExp(regExp);
Но, всё равно, отбор происходит по корневому списку и всё! Напишите подробнее что вы сделали?
Название: Re: QSortFilterProxyModel для древовидной модели
Отправлено: Странник от Февраль 03, 2012, 11:29
модель создаю так: proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(model); proxyModel->setFilterKeyColumn(0); proxyModel->setFilterRole(Qt::UserRole + 1);
при обновлении данных: proxyModel->sourceModel()->reset(); proxyModel->setFilterFixedString(filterString); proxyModel->sort(0);
dynamicSortFilter, как видим, отключен.
Название: Re: QSortFilterProxyModel для древовидной модели
Отправлено: schmidt от Март 13, 2012, 07:06
Проблема решается банальным наследованием от QSortFilterProxyModel и переопределением filterAcceptsRow(), работает это так: фильтр проверяет текущий нод, если его текст удовлетворяет regExp'у либо нод имеет хотя бы одного потомка, который этому фильтру удовлетворяет, то он будет отображен. /* * This file is part of DbAssistant distribution licensed under General Public License version 3 (GPLv3). * You may copy and redistribute it according to the terms of original license. This software comes * WITHOUT ANY WARRANTY but intended to be useful. Text of GPL license always can be found shipped with * DbAssistant distribution or at GNU Website (http://www.gnu.org/). Visit DbAssistant homepage to get more * information about it (http://dbassistant.sourceforge.net/).
* Author: Schmidt A. * License: GPLv3 * Date: Tue Mar 12 01:59:18 2012 */
#ifndef TREESORTFILTERMODEL_H #define TREESORTFILTERMODEL_H
#include <QSortFilterProxyModel>
#include "treenode.h" #include "sqldatabase.h" #include "sqltable.h" #include "sqlattribute.h" #include "webpage.h" #include "sqlform.h" #include "sqlformfield.h" #include "sqlformfieldgroup.h" #include "sqldisplay.h" #include "sqlquery.h" #include "datasource.h" #include "sqlqueryfield.h"
class TreeSortFilterModel : public QSortFilterProxyModel { Q_OBJECT
QRegExp* re_filter;
bool isNodeMatchesFilter(TreeNode* node) const;
public: explicit TreeSortFilterModel(QObject *parent = 0); QModelIndex mapToSource(const QModelIndex &proxyIndex) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
signals:
public slots: void updateFilterPattern(QString); void resetSearch();
};
/* * This file is part of DbAssistant distribution licensed under General Public License version 3 (GPLv3). * You may copy and redistribute it according to the terms of original license. This software comes * WITHOUT ANY WARRANTY but intended to be useful. Text of GPL license always can be found shipped with * DbAssistant distribution or at GNU Website (http://www.gnu.org/). Visit DbAssistant homepage to get more * information about it (http://dbassistant.sourceforge.net/).
* Author: Schmidt A. * License: GPLv3 * Date: Tue Mar 12 01:59:18 2012 */
#include "treesortfiltermodel.h"
TreeSortFilterModel::TreeSortFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { re_filter = new QRegExp(".*", Qt::CaseInsensitive); } /////////////////////////////////////////////////////////////////////////// void TreeSortFilterModel::updateFilterPattern(QString patt) { if(patt.isEmpty()) { resetSearch(); } else { re_filter->setPattern(patt); invalidateFilter(); } } /////////////////////////////////////////////////////////////////////////// void TreeSortFilterModel::resetSearch() { re_filter->setPattern(".*"); invalidateFilter(); } /////////////////////////////////////////////////////////////////////////// bool TreeSortFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { bool child_matches_filter = false; /* if(!source_parent.isValid()) { return true; } */ // TreeNode* parent_node; QModelIndex asked_index = sourceModel()->index(source_row, 0, source_parent); TreeNode* asked_node = static_cast<TreeNode*>(asked_index.internalPointer());
foreach(QObject* child, asked_node->children()) { TreeNode* child_node = static_cast<TreeNode*>(child); if(child_matches_filter = isNodeMatchesFilter(child_node)) { break; } }
if(child_matches_filter) // if item has at least one appropriate child, show it { return true; } else { // or check if it matches filter return isNodeMatchesFilter(asked_node); } } /////////////////////////////////////////////////////////////////////////// bool TreeSortFilterModel::isNodeMatchesFilter(TreeNode *node) const { bool result; SqlDatabase* db; SqlTable* table; SqlAttribute* attrib; WebPage* page; SqlForm* form; SqlFormField* ff; SqlFormFieldGroup* ffg; SqlDisplay* display; SqlQuery* query; SqlQueryField* qf; DataSource* data_source;
switch(node->type()) { case T_SQLDB: db = static_cast<SqlDatabase*>(node); result = re_filter->indexIn(db->alias()) != -1; break; case T_SQLTABLE: table = static_cast<SqlTable*>(node); result = re_filter->indexIn(table->alias()) != -1; break; case T_SQLATTRIB: attrib = static_cast<SqlAttribute*>(node); result = re_filter->indexIn(attrib->alias()) != -1; break; case T_WEBPAGE: page = static_cast<WebPage*>(node); result = re_filter->indexIn(page->name()) != -1; break; case T_SQLFORM: form = static_cast<SqlForm*>(node); result = re_filter->indexIn(form->name()) != -1; break; case T_SQLFORMFIELD: ff = static_cast<SqlFormField*>(node); result = re_filter->indexIn(ff->name()) != -1; break; case T_SQLFORMFIELDGROUP: ffg = static_cast<SqlFormFieldGroup*>(node); result = re_filter->indexIn(ffg->name()) != -1; break; case T_SQLDISPLAY: display = static_cast<SqlDisplay*>(node); result = re_filter->indexIn(display->name()) != -1; break; case T_SQLQUERY: query = static_cast<SqlQuery*>(node); result = re_filter->indexIn(query->name()) != -1; break; case T_SQLQUERYFIELD: qf = static_cast<SqlQueryField*>(node); result = re_filter->indexIn(qf->alias()) != -1; break; case T_DATASOURCE: data_source = static_cast<DataSource*>(node); result = re_filter->indexIn(data_source->name()) != -1; break; }
return result; } /////////////////////////////////////////////////////////////////////////// QModelIndex TreeSortFilterModel::mapToSource(const QModelIndex &proxyIndex) const { return QSortFilterProxyModel::mapToSource(proxyIndex); } /////////////////////////////////////////////////////////////////////////// QModelIndex TreeSortFilterModel::mapFromSource(const QModelIndex &sourceIndex) const { return QSortFilterProxyModel::mapFromSource(sourceIndex); } ///////////////////////////////////////////////////////////////////////////
|