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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: QSortFilterProxyModel для древовидной модели  (Прочитано 7866 раз)
Странник
Гость
« : Декабрь 05, 2011, 15:23 »

имеется кастомная древовидная модель, унаследованная от QAbstractItemModel. для сортировки и фильтрации предполагалось использовать QSortFilterProxyModel, но обнаружились грабли - сортировка работает по всему дереву, а фильтрация - только для элементов первого уровня (с родительским индексом QModelIndex()). так оно и задумано или криво реализована кастомная модель?
« Последнее редактирование: Декабрь 05, 2011, 15:26 от Странник » Записан
_OLEGator_
Гость
« Ответ #1 : Декабрь 05, 2011, 15:32 »

Криво реализовал.
Дай код посмотреть.
Записан
Странник
Гость
« Ответ #2 : Декабрь 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 возвращает верный индекс. какие-то тонкости работы с индексами прокси модели или просто баг?
Записан
Carobey
Гость
« Ответ #3 : Февраль 02, 2012, 19:33 »

Добрый день. Возникла аналогичная проблема!
Попробовал как Вы написали:
Код:
QRegExp regExp(arg1, Qt::CaseInsensitive);
proxy->sourceModel()->reset_();
proxy->setFilterRegExp(regExp);
Но, всё равно, отбор происходит по корневому списку и всё!
Напишите подробнее что вы сделали?
« Последнее редактирование: Февраль 02, 2012, 19:36 от Carobey » Записан
Странник
Гость
« Ответ #4 : Февраль 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, как видим, отключен.
Записан
schmidt
Гость
« Ответ #5 : Март 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);
}
///////////////////////////////////////////////////////////////////////////

Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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